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