Kyle Oppenheim wrote:
I assume you are running this script under Apache::Registry (since your URLs
have .pl extensions). Apache::Registry compiles your code into a subroutine
and runs it using this code:

my $old_status = $r->status;
my $cv = \&{"$package\::handler"};
eval { &{$cv}($r, @_) } if $r->seqno;
... snip ...
return $r->status($old_status);

Notice that it throws away the result of the eval {}, so it doesn't really
matter what you return. However, you can use $r->status from your script to
set the status code. Apache::Registry will return the value you set via
$r->status from it's handler() method. (I'm not sure why it's trying to set
$old_status at the same time.
$r->status($old_status) resets $r->status to $old_status while returning the current value (before the set) of $r->status. this is required because you're not supposed to mess with $r->status at all - it's merely a workaround that Apache::Registry uses and that real handlers are not supposed to.

If you look at the XS code it's clear that
$r->status returns the previously set value.  Anybody know the reason?)
basically, apache sets $r->status to 200 (HTTP_OK) before anybody is allowed to do anything. if you return SERVER_ERROR from your handler, Apache sets $r->status to 500. but, if (after that) you use an ErrorDocument to handle the error, that $r->status isn't 200 is Apache's way of telling that you are in an ErrorDocument cycle so that it doesn't infinitely recurse into more ErrorDocuments.

so again, this is why handlers don't ever set $r->status for real.

Also, Apache will call send_error_response for all 204, 3xx, 4xx, and 5xx
status codes.  So, you shouldn't call send_http_header in these cases.

Finally, you probably also want to set the Last-Modified header for HTTP/1.0
clients that don't understand ETag headers.  You can use $r->update_mtime
and $r->set_last_modified.

So, try the following change to your code:

    $R->content_type ($data {mimetype});
    $R->set_content_length ($data {size});
    $R->header_out ('ETag',$data {md5});
don't do that. use the $r->set_etag method instead, which is probably a bit safer than trying to figure out Etag rules yourself. I'm pretty sure that you shouldn't use the Etag header with non-static entities anyway, but I could be wrong.

    $R->update_mtime($data {mtime});
    $R->set_last_modified;

    if ((my $rc = $R->meets_conditions) != OK) {
        $R->status($rc);
and, again, don't do that unless you're using Apache::Registry. all the rest looks right.

there are a few recipes in the cookbook that may help as well, since they also illustrate various conditional processing idioms:

http://www.modperlcookbook.org/code/ch06/Cookbook/SendSmart.pm
http://www.modperlcookbook.org/code/ch08/Cookbook-Clean-0.03/Clean.pm

for example.

HTH

--Geoff

Reply via email to