You are viewing a plain text version of this content. The canonical link for it is here.
Posted to modperl@perl.apache.org by Torsten Förtsch <to...@gmx.net> on 2004/10/21 21:21:54 UTC
[mp2] $filter->remove patch
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Hi,
the attached patch makes Apache::Filter::remove work also for nativ filters.
Why do I need this?
First, from a users point of view it is not very understandable why a mod_perl
filter can be removed but a native filter (eg. INCLUDES) cannot.
My actual problem is the following. I have got some CGI and mod_perl scripts
that generate HTML and images. The HTML output should be filtered by INCLUDES
and a mod_perl filter, the images should be filtered only by my mod_perl
filter. The mod_perl filter must be called _after_ INCLUDES.
If I "AddOutputFilterByType INCLUDES text/html" the INCLUDES filter is called
_before_ the mod_perl filter. If I use PerlSetOutputFilter the filters are
called in the right order but INCLUDES is called for all documents.
There are multiple solutions. I could patch mod_include or add a
PerlAddOutputFilterByType directive or just use the existing
PerlSetOutputFilter and write a little filter that checks the requests
content-type and removes the next filter in the chain if needed:
PerlOutputFilterHandler Apache::Opis::RemoveNextFilterIfNotTextHtml
PerlSetOutputFilter INCLUDES
PerlOutputFilterHandler Apache::Opis::MyFilter
where Apache::Opis::MyFilter is the filter that needs to be called after
INCLUDES. The removing filter looks like:
- --------------------------------------------------------------------
package Apache::Opis::RemoveNextFilterIfNotTextHtml;
use strict;
use Apache::Filter ();
use Apache::FilterRec ();
use Apache::RequestRec ();
use Apache::Const -compile => qw(OK DECLINED);
sub handler {
my $f = shift;
my $r = $f->r;
unless( $r->content_type =~ m!text/html!i ) {
eval {
$f->next->remove;
};
warn $@ if $@;
}
$f->remove;
return Apache::DECLINED;
}
1;
- --------------------------------------------------------------------
This code fails with INCLUDES because mod_include is not a mod_perl filter.
Hence I had to patch Apache::Filter::remove.
Torsten
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.4 (GNU/Linux)
iD8DBQFBeAxWwicyCTir8T4RAnqyAJ0UW7ky8Z4ApZND9SDpX+LMNzijuACfZwkM
fQvJW0WchvJo9MsUvJmCoos=
=mizK
-----END PGP SIGNATURE-----
Re: [mp2] $filter->remove patch
Posted by Stas Bekman <st...@stason.org>.
Torsten Förtsch wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> On Friday 22 October 2004 19:10, Stas Bekman wrote:
>
>>>I thought about it this night and realized that I need not to traverse
>>>these lists at all. At first ist was a try to guess what to call
>>>ap_input_filter_remove or ap_output_filter_remove. But if the filter is
>>>not in an appropriate chain these functions do simply nothing. Hence I
>>>can call them both if I don't know what kind of filter it is.
>>
>>I wish we could somehow know what kind of filter is in question. In which
>>case we won't have needed to run wasteful CPU cycles. BTW, I've reversed
>>the order of removal, since I believe we will have many more output
>>filters than input ones. What do you think?
>
>
> Yes, I agree that there will be much more output filters but since we cannot
> not determine if ap_remove_output_filter has actually removed the filter we
> have to call ap_remove_input_filter in any case. Hence the calling order is
> all the same.
Hmm, haven't thought of that :)
Thanks again
--
__________________________________________________________________
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
--
Report problems: http://perl.apache.org/bugs/
Mail list info: http://perl.apache.org/maillist/modperl.html
List etiquette: http://perl.apache.org/maillist/email-etiquette.html
Re: [mp2] $filter->remove patch
Posted by Torsten Förtsch <to...@gmx.net>.
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
On Friday 22 October 2004 19:10, Stas Bekman wrote:
> > I thought about it this night and realized that I need not to traverse
> > these lists at all. At first ist was a try to guess what to call
> > ap_input_filter_remove or ap_output_filter_remove. But if the filter is
> > not in an appropriate chain these functions do simply nothing. Hence I
> > can call them both if I don't know what kind of filter it is.
>
> I wish we could somehow know what kind of filter is in question. In which
> case we won't have needed to run wasteful CPU cycles. BTW, I've reversed
> the order of removal, since I believe we will have many more output
> filters than input ones. What do you think?
Yes, I agree that there will be much more output filters but since we cannot
not determine if ap_remove_output_filter has actually removed the filter we
have to call ap_remove_input_filter in any case. Hence the calling order is
all the same.
> > The attached patch contains the updated Apache__Filter.h and a test that
> > removes INCLUDES from the output chain and DEFLATE from input.
>
> Excellent. I've massaged both quite a bit to adher to the style and
> simplify where it made sense (And found a perl bug in regex qr//m on the
> way :( see my latest report to p5p)
Looks good to me
> I'll commit it as soon as Philippe releases 1.99_17 (today?)
Thanks
Torsten
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.4 (GNU/Linux)
iD8DBQFBeVL0wicyCTir8T4RAiCiAKCT1gXWqPle5r08q7BSSFEhYKvr7QCdGedI
Nszf0Y4AANkitUcjzn2CeDM=
=iQl2
-----END PGP SIGNATURE-----
--
Report problems: http://perl.apache.org/bugs/
Mail list info: http://perl.apache.org/maillist/modperl.html
List etiquette: http://perl.apache.org/maillist/email-etiquette.html
Re: [mp2] $filter->remove patch
Posted by Stas Bekman <st...@stason.org>.
Stas Bekman wrote:
[...]
>> The attached patch contains the updated Apache__Filter.h and a test
>> that removes INCLUDES from the output chain and DEFLATE from input.
>
>
> Excellent. I've massaged both quite a bit to adher to the style and
> simplify where it made sense (And found a perl bug in regex qr//m on the
> way :( see my latest report to p5p)
>
> I'll commit it as soon as Philippe releases 1.99_17 (today?)
Now committed. Thanks Torsten.
--
__________________________________________________________________
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
--
Report problems: http://perl.apache.org/bugs/
Mail list info: http://perl.apache.org/maillist/modperl.html
List etiquette: http://perl.apache.org/maillist/email-etiquette.html
Re: [mp2] $filter->remove patch
Posted by Stas Bekman <st...@stason.org>.
Torsten Förtsch wrote:
>>but why do you need to traverse all these lists? is it because we don't
>>know whether the given filter is an input filter or output one? May be
>>it's easier to attach some flag to the filter object to say which kind of
>>filter is that?
>
>
> I thought about it this night and realized that I need not to traverse these
> lists at all. At first ist was a try to guess what to call
> ap_input_filter_remove or ap_output_filter_remove. But if the filter is not
> in an appropriate chain these functions do simply nothing. Hence I can call
> them both if I don't know what kind of filter it is.
I wish we could somehow know what kind of filter is in question. In which
case we won't have needed to run wasteful CPU cycles. BTW, I've reversed
the order of removal, since I believe we will have many more output
filters than input ones. What do you think?
> The attached patch contains the updated Apache__Filter.h and a test that
> removes INCLUDES from the output chain and DEFLATE from input.
Excellent. I've massaged both quite a bit to adher to the style and
simplify where it made sense (And found a perl bug in regex qr//m on the
way :( see my latest report to p5p)
I'll commit it as soon as Philippe releases 1.99_17 (today?)
Index: Changes
===================================================================
RCS file: /home/cvs/modperl-2.0/Changes,v
retrieving revision 1.513
diff -u -u -r1.513 Changes
--- Changes 15 Oct 2004 19:26:06 -0000 1.513
+++ Changes 22 Oct 2004 17:07:51 -0000
@@ -12,6 +12,9 @@
=item 1.99_17-dev
+$filter->remove now works with native (non-modperl) filters + test
+[Torsten Förtsch <torsten.foertsch gmx.net>]
+
fix xs_generate to croak on duplicate entries in xs/maps files
[Christian Krause <chkr plauener.de>]
Index: xs/Apache/Filter/Apache__Filter.h
===================================================================
RCS file: /home/cvs/modperl-2.0/xs/Apache/Filter/Apache__Filter.h,v
retrieving revision 1.42
diff -u -u -r1.42 Apache__Filter.h
--- xs/Apache/Filter/Apache__Filter.h 1 Oct 2004 03:30:12 -0000 1.42
+++ xs/Apache/Filter/Apache__Filter.h 22 Oct 2004 17:07:54 -0000
@@ -284,7 +284,28 @@
modperl_filter_t *modperl_filter;
ap_filter_t *f;
- mpxs_usage_va_1(modperl_filter, "$filter->remove()");
+ if (items < 1) {
+ Perl_croak(aTHX_ "usage: $filter->remove()");
+ }
+
+ modperl_filter = mp_xs_sv2_modperl_filter(*MARK);
+
+ /* native filter */
+ if (!modperl_filter) {
+ f = (ap_filter_t*)SvIV(SvRV(*MARK));
+ MP_TRACE_f(MP_FUNC,
+ " %s\n\n\t non-modperl filter removes itself\n",
+ f->frec->name);
+
+ /* the filter can reside in only one chain. hence we try to
+ * remove it first from the output chains (more likely to be
+ * the one) then from the input chains.
+ */
+ ap_remove_output_filter(f);
+ ap_remove_input_filter(f);
+ return;
+ }
+
f = modperl_filter->f;
MP_TRACE_f(MP_FUNC, " %s\n\n\tfilter removes itself\n",
--- /dev/null 1969-12-31 19:00:00.000000000 -0500
+++ t/filter/both_str_native_remove.t 2004-10-22 12:43:40.071433961 -0400
@@ -0,0 +1,59 @@
+use strict;
+use warnings FATAL => 'all';
+
+use Apache::Test;
+use Apache::TestRequest;
+use Apache::TestUtil;
+
+plan tests => 8, need 'deflate', 'include',
+ need_min_module_version("Compress::Zlib", "1.09");
+
+require Compress::Zlib;
+
+my $base = '/TestFilter__both_str_native_remove';
+
+# 1. check if DEFLATE input and INCLUDES output filter work
+{
+ my $location = $base;
+ my $received = POST_BODY $location,
+ content => Compress::Zlib::memGzip('gzipped text'),
+ 'Content-Encoding' => "gzip";
+
+ ok t_cmp $received, qr/xSSI OK/, "INCLUDES filter";
+
+ ok t_cmp $received, qr/content: gzipped text/, "DEFLATE filter";
+}
+
+
+# 2. check if DEFLATE input and INCLUDES output filter can be removed
+{
+ my $location = "$base?remove";
+ my $received = POST_BODY $location, content => 'plain text';
+
+ ok t_cmp $received,
+ qr/input1: [\w,]+deflate/,
+ "DEFLATE filter is present";
+
+ ok !t_cmp $received,
+ qr/input2: [\w,]+deflate/,
+ "DEFLATE filter is removed";
+
+ ok t_cmp $received,
+ qr/content: plain text/,
+ "DEFLATE filter wasn't invoked";
+
+ ok t_cmp $received,
+ qr/output1: modperl_request_output,includes,modperl_request_output,/,
+ "INCLUDES filter is present";
+
+ ok t_cmp $received,
+ qr/output2: modperl_request_output,(?!includes)/,
+ "INCLUDES filter is removed";
+
+ ok t_cmp $received,
+ qr/x<!--#echo var="SSI_TEST" -->x/,
+ "INCLUDES filter wasn't invoked";
+
+}
+
+
--- /dev/null 1969-12-31 19:00:00.000000000 -0500
+++ t/filter/TestFilter/both_str_native_remove.pm 2004-10-22
13:02:11.096991308 -0400
@@ -0,0 +1,137 @@
+package TestFilter::both_str_native_remove;
+
+# this tests verifies that we can remove input and output native
+# (non-mod_perl filters)
+
+use strict;
+use warnings FATAL => 'all';
+
+use Apache::RequestRec ();
+use Apache::RequestIO ();
+
+use Apache::Filter ();
+use Apache::FilterRec ();
+
+use Apache::Const -compile => qw(OK DECLINED);
+
+# this filter removes the next filter in chain and itself
+sub remove_includes {
+ my $f = shift;
+
+ my $args = $f->r->args || '';
+ if ($args eq 'remove') {
+ my $ff = $f->next;
+ $ff->remove if $ff && $ff->frec->name eq 'includes';
+ }
+
+ $f->remove;
+
+ return Apache::DECLINED;
+}
+
+# this filter removes the next filter in chain and itself
+sub remove_deflate {
+ my $f = shift;
+
+ my $args = $f->r->args || '';
+ if ($args eq 'remove') {
+ for (my $ff = $f->r->input_filters; $ff; $ff = $ff->next) {
+ if ($ff->frec->name eq 'deflate') {
+ $ff->remove;
+ last;
+ }
+ }
+ }
+ $f->remove;
+
+ return Apache::DECLINED;
+}
+
+# this filter appends the output filter list at eos
+sub print_out_flist {
+ my $f = shift;
+
+ unless ($f->ctx) {
+ $f->ctx(1);
+ $f->r->headers_out->unset('Content-Length');
+ }
+
+ while ($f->read(my $buffer, 1024)) {
+ $f->print($buffer);
+ }
+
+ if ($f->seen_eos) {
+ my $flist = join ',', get_flist($f->r->output_filters);
+ $f->print("output2: $flist\n");
+ }
+
+ return Apache::OK;
+}
+
+sub store_in_flist {
+ my $f = shift;
+ my $r = $f->r;
+
+ unless ($f->ctx) {
+ my $x = $r->pnotes('INPUT_FILTERS') || [];
+ push @$x, join ',', get_flist($f->r->input_filters);
+ $r->pnotes('INPUT_FILTERS' => $x);
+ }
+
+ return Apache::DECLINED;
+}
+
+
+sub response {
+ my $r = shift;
+
+ # just to make sure that print() won't flush, or we would get the
+ # count wrong
+ local $| = 0;
+
+ $r->content_type('text/plain');
+ if ($r->method_number == Apache::M_POST) {
+ $r->print("content: " . ModPerl::Test::read_post($r) ."\n");
+ }
+
+ my $i=1;
+ for (@{ $r->pnotes('INPUT_FILTERS')||[] }) {
+ $r->print("input$i: $_\n");
+ $i++;
+ }
+
+ $r->subprocess_env(SSI_TEST => 'SSI OK');
+ $r->printf("output1: %s\n", join ',', get_flist($r->output_filters));
+
+ $r->rflush; # this sends the data in the buffer + flush bucket
+ $r->print('x<!--#echo var=');
+ $r->rflush; # this sends the data in the buffer + flush bucket
+ $r->print('"SSI_TEST" -->x'."\n");
+
+ Apache::OK;
+}
+
+sub get_flist {
+ my $f = shift;
+
+ my @flist = ();
+ for (; $f; $f = $f->next) {
+ push @flist, $f->frec->name;
+ }
+
+ return @flist;
+}
+
+1;
+__DATA__
+Options +Includes
+SetHandler modperl
+PerlModule TestFilter::both_str_native_remove
+PerlResponseHandler TestFilter::both_str_native_remove::response
+PerlOutputFilterHandler TestFilter::both_str_native_remove::remove_includes
+PerlSetOutputFilter INCLUDES
+PerlOutputFilterHandler TestFilter::both_str_native_remove::print_out_flist
+PerlInputFilterHandler TestFilter::both_str_native_remove::store_in_flist
+PerlInputFilterHandler TestFilter::both_str_native_remove::remove_deflate
+PerlSetInputFilter DEFLATE
+PerlInputFilterHandler TestFilter::both_str_native_remove::store_in_flist
--
__________________________________________________________________
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
--
Report problems: http://perl.apache.org/bugs/
Mail list info: http://perl.apache.org/maillist/modperl.html
List etiquette: http://perl.apache.org/maillist/email-etiquette.html
Re: [mp2] $filter->remove patch
Posted by Torsten Förtsch <to...@gmx.net>.
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
On Friday 22 October 2004 00:38, Stas Bekman wrote:
> Torsten F�rtsch wrote:
> > + � �if( f->c ) {
> > +�����for( list=f->c->input_filters; list; list=list->next ) {
> > +����� � �if( list==f ) {
> > +�������������ap_remove_input_filter(f);
> > +�������������return;
> > +����� � �}
> > +�����}
> > + � �}
>
> [ snipped other filter chains traversals ]
>
> but why do you need to traverse all these lists? is it because we don't
> know whether the given filter is an input filter or output one? May be
> it's easier to attach some flag to the filter object to say which kind of
> filter is that?
I thought about it this night and realized that I need not to traverse these
lists at all. At first ist was a try to guess what to call
ap_input_filter_remove or ap_output_filter_remove. But if the filter is not
in an appropriate chain these functions do simply nothing. Hence I can call
them both if I don't know what kind of filter it is.
> > +static MP_INLINE
> > �void mpxs_Apache__Filter_remove(pTHX_ I32 items, SV **MARK, SV **SP)
> > �{
> > � � �modperl_filter_t *modperl_filter;
> > � � �ap_filter_t *f;
> > �
> > - � �mpxs_usage_va_1(modperl_filter, "$filter->remove()");
> > + � �if (items < 1) {
> > + � � � �Perl_croak(aTHX_ "usage: $filter->remove()");
> > + � �}
> > +
> > + � �modperl_filter = mp_xs_sv2_modperl_filter(*MARK);
> > +
> > + � �if( !modperl_filter ) {��/* native filter */
> > + � � � �mpxs_Apache__Filter_remove_native_filter(aTHX_
> > (ap_filter_t*)SvIV(SvRV(*MARK))); +�����return;
> > + � �}
> > +
> > � � �f = modperl_filter->f;
> > �
> > � � �MP_TRACE_f(MP_FUNC, " � %s\n\n\tfilter removes itself\n",
>
> Also if you could add a test, that will save some time to us. e.g. take
> the t/filter/TestFilter/both_str_req_mix.pm as the base (could probably
> simplify it a bit to just test that it can be removed both on input and
> output). to make your work easier you could just start messing with this
> test and then post it or if you know A-T better you could start a new test
The attached patch contains the updated Apache__Filter.h and a test that
removes INCLUDES from the output chain and DEFLATE from input.
Torsten
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.4 (GNU/Linux)
iD8DBQFBeQbrwicyCTir8T4RAtq3AJ9Gpdal0wooCpAST5MYY92dJmueLwCfffB8
KnDaSw1Xs7JDLBQNICt0b5Y=
=YYFu
-----END PGP SIGNATURE-----
Re: [mp2] $filter->remove patch
Posted by Stas Bekman <st...@stason.org>.
Torsten Förtsch wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> Hi,
>
> the attached patch makes Apache::Filter::remove work also for nativ filters.
>
> Why do I need this?
[explanation snipped]
I see no reason why we shouldn't support that.
> --- mod_perl-1.99_16/xs/Apache/Filter/Apache__Filter.h~ 2004-07-12 09:32:07.000000000 +0200
> +++ mod_perl-1.99_16/xs/Apache/Filter/Apache__Filter.h 2004-10-21 13:52:13.243774248 +0200
> @@ -277,12 +277,85 @@
> }
>
> static MP_INLINE
> +void mpxs_Apache__Filter_remove_native_filter(pTHX_ ap_filter_t* f)
> +{
> + ap_filter_t *list;
> +
> + if( f->c ) {
> + for( list=f->c->input_filters; list; list=list->next ) {
> + if( list==f ) {
> + ap_remove_input_filter(f);
> + return;
> + }
> + }
> + }
[ snipped other filter chains traversals ]
but why do you need to traverse all these lists? is it because we don't
know whether the given filter is an input filter or output one? May be
it's easier to attach some flag to the filter object to say which kind of
filter is that?
> +static MP_INLINE
> void mpxs_Apache__Filter_remove(pTHX_ I32 items, SV **MARK, SV **SP)
> {
> modperl_filter_t *modperl_filter;
> ap_filter_t *f;
>
> - mpxs_usage_va_1(modperl_filter, "$filter->remove()");
> + if (items < 1) {
> + Perl_croak(aTHX_ "usage: $filter->remove()");
> + }
> +
> + modperl_filter = mp_xs_sv2_modperl_filter(*MARK);
> +
> + if( !modperl_filter ) { /* native filter */
> + mpxs_Apache__Filter_remove_native_filter(aTHX_ (ap_filter_t*)SvIV(SvRV(*MARK)));
> + return;
> + }
> +
> f = modperl_filter->f;
>
> MP_TRACE_f(MP_FUNC, " %s\n\n\tfilter removes itself\n",
Also if you could add a test, that will save some time to us. e.g. take
the t/filter/TestFilter/both_str_req_mix.pm as the base (could probably
simplify it a bit to just test that it can be removed both on input and
output). to make your work easier you could just start messing with this
test and then post it or if you know A-T better you could start a new test
--
__________________________________________________________________
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
--
Report problems: http://perl.apache.org/bugs/
Mail list info: http://perl.apache.org/maillist/modperl.html
List etiquette: http://perl.apache.org/maillist/email-etiquette.html