Potentially infinte output
In this article I'll describe bucket brigade based output in a PerlResponseHandler. This technique
can be used similar to the simpler stream based IO that is usually used. As an example I'll implement a browser
clock based on HTTP Server Push.
Here is a first solution that uses stream based IO via $r->print:
sub handler {
my ($r)=@_;
my $boundary='The Final Frontier';
$r->content_type(qq{multipart/x-mixed-replace;boundary="$boundary";});
$boundary="--$boundary\n";
my $mpheader=<<'HEADER';
Content-type: text/html; charset=UTF-8;
HEADER
for(1..100) {
$r->print($boundary);
$r->print($mpheader);
my $msg='<html><body><h1>'.localtime()."</h1></body></html>\n";
$r->print($msg);
$r->rflush;
sleep 1;
}
$r->print($boundary);
return Apache2::Const::OK;
}
There is nothing wrong with this code except if you change the for(1..100) into a really infinite while(1) loop
you'll notice that the httpd process size increases over time also without limits. This is considered a bug and there is hope
that it will be resolved some day.
But fortunately it's quite easy to replace the stream based IO by bucket brigades, the underlying Apache interface. Thus, the bug can be circumvented:
sub handler {
my ($r)=@_;
my $boundary='The Final Frontier';
$r->content_type(qq{multipart/x-mixed-replace;boundary="$boundary";});
$boundary="--$boundary\n";
my $mpheader=<<'HEADER';
Content-type: text/html; charset=UTF-8;
HEADER
my $ba=$r->connection->bucket_alloc;
my $bb=APR::Brigade->new($r->pool, $ba);
while(1) {
$bb->insert_tail(APR::Bucket->new($ba, $boundary));
$bb->insert_tail(APR::Bucket->new($ba, $mpheader));
my $msg='<html><body><h1>'.localtime()."</h1></body></html>\n";
$bb->insert_tail(APR::Bucket->new($ba, $msg));
$bb->insert_tail(APR::Bucket::flush_create $ba);
$r->output_filters->pass_brigade($bb);
$bb->cleanup;
sleep 1;
}
$bb->insert_tail(APR::Bucket->new($ba, $boundary));
$bb->insert_tail(APR::Bucket::eos_create $ba);
$r->output_filters->pass_brigade($bb);
return Apache2::Const::OK;
}
The clock is available here. But it ticks for only 30 seconds due to the limited resources of my server.
Thanks to all who has worked on the solution, see http://www.gossamer-threads.com/lists/modperl/modperl/101225
Letzte Aktualisierung: 20.03.2010

