stas 2003/08/26 21:42:38
Modified: t/filter in_str_consume.t t/filter/TestFilter in_str_consume.pm Log: rewrite the input streaming consume filter to bring it up-to-date with the latest httpds. make it more elaborate at the same time. Revision Changes Path 1.3 +7 -4 modperl-2.0/t/filter/in_str_consume.t Index: in_str_consume.t =================================================================== RCS file: /home/cvs/modperl-2.0/t/filter/in_str_consume.t,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- in_str_consume.t 18 Apr 2003 06:18:56 -0000 1.2 +++ in_str_consume.t 27 Aug 2003 04:42:37 -0000 1.3 @@ -1,6 +1,8 @@ use strict; use warnings FATAL => 'all'; +# see the explanations in in_str_consume.pm + use Apache::Test; use Apache::TestUtil; use Apache::TestRequest; @@ -9,10 +11,11 @@ my $location = '/TestFilter__in_str_consume'; -# send a message bigger than 8k, so to make sure that the input filter -# will get more than one bucket brigade with data. -my $data = "A 22 chars long string" x 500; # about 11k +my $data = "*" x 80000; # about 78K => ~10 bbs +my $expected = 105; + +t_debug "sent " . length($data) . "B, expecting ${expected}B to make through"; + my $received = POST_BODY $location, content => $data; -my $expected = "read just the first 1024b from the first brigade"; ok t_cmp($expected, $received, "input stream filter partial consume") 1.8 +77 -44 modperl-2.0/t/filter/TestFilter/in_str_consume.pm Index: in_str_consume.pm =================================================================== RCS file: /home/cvs/modperl-2.0/t/filter/TestFilter/in_str_consume.pm,v retrieving revision 1.7 retrieving revision 1.8 diff -u -r1.7 -r1.8 --- in_str_consume.pm 22 Aug 2003 19:15:08 -0000 1.7 +++ in_str_consume.pm 27 Aug 2003 04:42:38 -0000 1.8 @@ -2,65 +2,94 @@ # this test verifies that streaming filters framework handles # gracefully the case when a filter doesn't print anything at all to -# the caller. I figure it absolutely doesn't matter if the incoming -# bb from the upstream is consumed or not. What matters is that the -# filter sends something downstream (an empty bb will do). -# +# the caller. + # the real problem is that in the streaming filters we can't consume -# more than one bucket brigade, which we can in non-stream filters., -# e.g. see in_bbs_underrun.pm +# more than one bucket brigade during a single filter invocation, +# which we can in non-stream filters., (e.g. see in_bbs_underrun.pm) +# +# it seems that this works just fine (2.0.46+) and older httpds +# had problems when a filter invocation hasn't printed a thing. +# +# currently if the streaming filter doesn't print anything, the +# upstream filter gets an empty brigade brigade (easily verified with +# the snooping debug filter). Of course if the filter returns +# Apache::DECLINED the unconsumed data will be passed to upstream filter +# +# this test receives about 10 bbs +# it reads only the first 23 bytes of each bb and discards the rest +# since it wants only 105 bytes it partially consumes only the first 5 bbs +# since it doesn't read all the data in, it'll never see EOS +# therefore once it has read all 105 bytes, it manually sets the EOS flag +# and the rest of the bbs are ignored, the filter is invoked only 5 times +# +# to debug this filter run it as: +# +# t/TEST -v -trace=debug filter/in_str_consume +# +# to enable upstream and downstream filter snooping, uncomment the +# snooping filters directives at the end of this file and rerun: +# t/TEST -conf +# +# to see what happens inside the filter, assuming that you built +# mod_perl with MP_TRACE=1, run: +# env MOD_PERL_TRACE=f t/TEST -v -trace=debug filter/in_str_consume # -# e.g. a filter that cleans up the incoming stream (extra spaces?) -# might reduce the whole bb into nothing (e.g. if it was made of only -# white spaces) then it should send "" down. -# -# another problem with not reading in the while() loop, is that the -# eos bucket won't be detected by the streaming framework and -# consequently won't be sent downstream, probably breaking other -# filters who rely on receiving the EOS bucket. use strict; use warnings FATAL => 'all'; use Apache::Filter (); +use Apache::TestTrace; use Apache::Const -compile => qw(OK M_POST); +use constant READ_BYTES_TOTAL => 105; +use constant READ_BYTES_FIRST => 23; + sub handler { my $filter = shift; - my $count = $filter->ctx || 0; + my $ctx = $filter->ctx || { data => '', count => '1'}; + debug "FILTER INVOKED: $ctx->{count}"; + + # read untill READ_BYTES read, no matter how many filter + # invocations it'll take + my $wanted_total = READ_BYTES_TOTAL - length $ctx->{data}; + my $wanted_current = READ_BYTES_FIRST; + my $wanted = $wanted_total; + $wanted = $wanted_current if $wanted > $wanted_current; + debug "total wanted: $wanted_total bytes"; + debug "this bb wanted: $wanted bytes"; + while ($wanted) { + my $len = $filter->read(my $buffer, $wanted); + $ctx->{data} .= $buffer; + $wanted_total -= $len; + $wanted -= $len; + debug "FILTER READ: $len ($wanted_total more to go)"; + last unless $len; # no more data to read in this bb + } + + $ctx->{count}++; - unless ($count) { - # read a bit from the first brigade and leave the second - # brigade completely unconsumed. we assume that there are two - # brigades because the core input filter will split data in - # 8kb chunks per brigade and we have sent 11k of data (1st bb: - # 8kb, 2nd bb: ~3kb) - my $len = $filter->read(my $buffer, 1024); - #warn "FILTER READ: $len bytes\n"; - $filter->print("read just the first 1024b from the first brigade"); + unless ($wanted_total) { + # we don't want to read the rest if there is anything left + $filter->seen_eos(1); + } - $filter->ctx(1); + if ($filter->seen_eos) { + # flush the data if we are done + $filter->print($ctx->{data}); } else { - $count++; - #warn "FILTER CALLED post $count time\n"; - unless ($filter->seen_eos) { - # XXX: comment out the next line to reproduce the segfault - $filter->print(""); - $filter->ctx($count); - } - - # this is not needed in newer Apache versions, however older - # versions (2.0.40) will repeatedly call this filter, waiting - # for EOS which will never come from this filter so, after - # several invocations mark the seen_eos flag, to break the - # vicious cirle - # BACK_COMPAT_MARKER: make back compat issues easy to find - if ($count > 10) { - $filter->seen_eos(1); - } + # store the data away + $filter->ctx($ctx); + + # notice that it seems to work even though we don't print + # anything. the upstream filter gets an empty bb. + + # alternatively could print the chunks of data that we read, + # if we don't need to have it as a whole chunk } return Apache::OK; @@ -73,8 +102,9 @@ if ($r->method_number == Apache::M_POST) { my $data = ModPerl::Test::read_post($r); - #warn "HANDLER READ: $data\n"; - $r->print($data); + my $len = length $data; + debug "HANDLER READ: $len bytes\n"; + $r->print($len); } return Apache::OK; @@ -84,3 +114,6 @@ SetHandler modperl PerlModule TestFilter::in_str_consume PerlResponseHandler TestFilter::in_str_consume::response +#PerlInputFilterHandler ModPerl::TestFilterDebug::snoop_request +PerlInputFilterHandler TestFilter::in_str_consume::handler +#PerlInputFilterHandler ModPerl::TestFilterDebug::snoop_request