[Catalyst] Bug in Catalyst::finalize_headers()

Bernhard Graf catalyst2 at augensalat.de
Sun May 6 11:02:51 GMT 2007


Next episode from my attempts in writing a serialization view class:

After I learned that finalize_body() can read from an object (that 
can('read')) or from a file handle, I implemented the idea of sending 
data through a pipe.

In short the View class does:

package CatalystX::View::DBIC;

use IO::Pipe;

sub process {
  my ($self, $c) = @_;

  [...]

  $pipe = new IO::Pipe;
  if ($pid = fork()) { # here's the parent
    $pipe->reader;     # parent reads from child
    $c->response->body($pipe);
    return;
  }
  # here's the child
  $pipe->writer;       # child writes to parent
  # read from the DBIC result set
  while ($row = $rs->next) {
    # write formatted (e.g. CSV) data into pipe
    $pipe->write($self->format($row, $columns));
  }
  close $pipe;
  exit(0);
}

The idea is that process() sets up the pipe, forks a sub process that 
does the long lasting reading from db and writeing into a pipe, whereas 
the parent stores the other end of the pipe handle into 
$c->response->body() and returns immediatly. Then finalize_body() would 
hopefully read from the pipe and write data to the browser as soon as 
the child process stores the first lines into the pipe.

Unfortunately this failed. Firefox only stored about 930 bytes, then 
dropped the connection whereas Konqueror didn't write anything.

Many hours later I discovered the reason: The response header had a line
Content-Length: 0
Aaargh!

This header line is automatically created by this code in 
Catalyst::finalize_headers():

  if ( my $stat = stat $c->response->body ) {
      $c->response->content_length( $stat->size );
  }

Apparently this assumes that $c->response->body is a filehandle of a 
regular file, but you can stat any kind of file (remember: "in UNIX 
everything is a file") and for a pipe $stat->size is 0!

I fixed the code and now it works as expected, though chunked 
transfer coding*) would be a nice feature in the absence of a 
Content-Length header.

A patch against the svn trunk is attached.

*) http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.6.1
-- 
Bernhard Graf
-------------- next part --------------
A non-text attachment was scrubbed...
Name: catalyst_finalize_headers.patch
Type: text/x-diff
Size: 819 bytes
Desc: not available
Url : http://lists.scsys.co.uk/pipermail/catalyst/attachments/20070506/9b1b84f0/catalyst_finalize_headers-0001.bin


More information about the Catalyst mailing list