On Thu, 21 Nov 2002, Stas Bekman wrote: > Esteban Fernandez Stafford wrote: > > > > Hello, > > > > I am currently developing a modperl filter that uses the streaming > > approach. I started off with the example in > > > > >http://perl.apache.org/docs/2.0/user/handlers/filters.html#Stream_oriented_Output_Filter > > > > sub handler { > > my $filter = shift; > > > > my $left_over = ''; > > while ($filter->read(my $buffer, BUFF_LEN)) { > > $buffer = $left_over . $buffer; > > $left_over = ''; > > while ($buffer =~ /([^\r\n]*)([\r\n]*)/g) { > > $left_over = $1, last unless $2; > > $filter->print(scalar(reverse $1), $2); > > } > > } > > $filter->print(scalar reverse $left_over) if length $left_over; > > > > Apache::OK; > > } > > > > This seems to work OK when the file is small (smaller than 8192). When > > the file is larger, then there is a line that gets cut. This is > > because the handler gets called more than once for big requests. Is > > there a nice way to overcome this problem? I was thinking using > > filter context to store variable $left_over, but then I dont know how > > to detect the "real" end of the stream. > > The problem is that I've written a patch that makes the $filter->print() > outside the while() loop work, but it was never committed. So the doc > is out of sync with the core code. For now please apply this patch: > http://marc.theaimsgroup.com/?l=apache-modperl-dev&m=102828686110352&w=2 > > I'll see that it gets into the core asap. >
Thanks Stas, the patch you sent me solved some of my trouble. The bad news is that I still have problems when I filter large files. I have written an example to expose this behaviour. It consists of modified versions of the beloved SendAlphaNum.pm and FilterReverse1.pm. ---------------------------------------------------- package MyApache::SendAlphaNum; use strict; use warnings; use Apache::RequestRec (); use Apache::RequestIO (); use Apache::Const -compile => qw(OK); sub handler { my $r = shift; $r->content_type('text/plain'); foreach(1..300) { $r->print(1..9, "0", 'a'..'z', "\n"); } Apache::OK; } 1; ---------------------------------------------------- package MyApache::FilterReverse1; use strict; use warnings; use base qw(Apache::Filter); use Apache::Const -compile => qw(OK); use constant BUFF_LEN => 1024; my $count = 0; sub handler { my $filter = shift; $filter->print("\nI'm Starting: $count bytes so far...\n"); my $left_over = ''; while ($filter->read(my $buffer, BUFF_LEN)) { $count+=length($buffer); $buffer = $left_over . $buffer; $left_over = ''; while ($buffer =~ /([^\r\n]*)([\r\n]*)/g) { $left_over = $1, last unless $2; $filter->print(scalar(reverse $1), $2); } } $filter->print(scalar reverse $left_over) if length $left_over; Apache::OK; } 1; ---------------------------------------------------- PerlModule MyApache::FilterReverse1 PerlModule MyApache::SendAlphaNum <Location /reverse1> SetHandler modperl PerlResponseHandler MyApache::SendAlphaNum PerlOutputFilterHandler MyApache::FilterReverse1 </Location> ---------------------------------------------------- As an output I get the following: $ wget -q -O - http://fangorn:3000/reverse1 I'm Starting: 0 bytes so far... zyxwvutsrqponmlkjihgfedcba0987654321 zyxwvutsrqponmlkjihgfedcba0987654321 # A lot of these... zyxwvutsrqponmlkjihgfedcba0987654321 zyxwvutsrqponmlkjihgfedcba0987654321 edcba0987654321 I'm Starting: 8192 bytes so far... zyxwvutsrqponmlkjihgf zyxwvutsrqponmlkjihgfedcba0987654321 zyxwvutsrqponmlkjihgfedcba0987654321 # ... and some more... zyxwvutsrqponmlkjihgfedcba0987654321 zyxwvutsrqponmlkjihgfedcba0987654321 As you can see the filter is called twice and therefore there is one line that gets broken in two. I could always store $left_over in the context of the filter and prepend it to what I read when the filter starts again. But the problem I find is that I have no way to know when the "real" eos is reached in order to flush $left_over to the output. I thought there may be some sort of $filter->eos() call or something. E s t e b a n! :wq