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



Reply via email to