modperl:
I found confirmation regarding the issue of headers getting lost on internal
redirection on p. 172 of the Eagle book:
"Another important detail about error handling is that Apache
ignores the fields that you set with header_out() when your module
generates an error status or invokes an internal redirect."
Reading further:
"For these cases, call the request object's err_header_out()
method. It has identical syntax to header_out(), but the fields
that you set with it are sent to the browser only when an error has
occurred. Unlike ordinary headers, the fields set with
err_header_out() persist across internal redirections..."
RTM perldoc Apache under $r->err_headers_out:
"The difference between headers_out and err_headers_out is that the
latter are printed even on error, and persist across internal redi-
rects (so the headers printed for ErrorDocument handlers will have
them).
So, I tried using err_headers_out to set "Pragma: no-cache" and "Cache-control:
no-cache" headers. wget sees them, but IE still displays the same picture. :-(
STFW:
http://support.microsoft.com/kb/q222064/
Interesting, but an unworkable "RESOLUTION". Looking some more:
http://support.microsoft.com/kb/q234067/
So, I added an "Expires: -1" header. Strange. It seemed to work for a few
clicks, and then got stuck. I guess this first few were the different Apache
children sending different pictures, but once the newest picture was sent, the
browser got stuck on its cache (?). Dig some more:
http://psacake.com/web/s.asp
Implement "Expires: 0" and Expiresabsolute as time() - 1. Nope. Not even a
teaser.
Try setting Expires to time() -1. Nope.
Try setting Expires to time() - 24*3600. Nope.
Dig some more:
http://www.phpbuilder.com/tips/item.php?id=123
Looks like it's worth giving a try. But, how do I set the same header three
times? Hmmm... Looks like err_header_out() doesn't accept an array ref, and
calling it multiple times just steps on previous values. After beating my head
against that for a while, it turns out that "Cache-control: max-age=0" seems to
be enough. It also looks like Expires and "Pragma: no-cache" are unnecessary.
So, to prevent caching in IE 6.0 SP2 when using Apache 1.3.33
internal_redirect(), call err_header_out() and set the "Last-Modified" header to
the current time and the "Cache-control" header to "max-age=0".
HTH,
David
#######################################################################
# $Id: RandomPicture.pm,v 1.7 2005/07/17 03:03:17 dpchrist Exp $
#
# Redirect to random picture per [1] pp. 123-128 using internal
# redirection and err_header_out().
#
# Copyright 2005 by David Christensen <[EMAIL PROTECTED]>
#
# References:
#
# [1] Lincoln Stein & Doug MacEachern, 1999, "Writing Apache Modules
# with Perl and C", O'Reilly, ISBN 1-56592-567-X.
#######################################################################
# Apache::NavBar package:
#----------------------------------------------------------------------
package Apache::RandomPicture;
#######################################################################
# uses:
#----------------------------------------------------------------------
use strict;
use warnings;
use Apache::Constants qw(:common REDIRECT DOCUMENT_FOLLOWS);
use Data::Dumper;
use DirHandle;
$Data::Dumper::Indent = 0;
#######################################################################
# package globals:
#----------------------------------------------------------------------
our $debug = 1;
our $picturedir_directive = 'PictureDir';
#######################################################################
# subroutines:
#----------------------------------------------------------------------
sub handler
{
$_[0]->log_error(sprintf("%s (%s %s): ",
(caller(0))[3], __FILE__, __LINE__),
Data::Dumper->Dump([EMAIL PROTECTED], [qw(*_)])) if $debug;
my $r = shift;
my $retval = DECLINED; ##### pessimistic execution
my $dir_uri = $r->dir_config($picturedir_directive);
unless ($dir_uri) {
$r->log_error(sprintf("%s (%s %s): ",
(caller(0))[3], __FILE__, __LINE__),
"unable to find Apache configuration directive ",
"'$picturedir_directive'");
goto done;
}
$dir_uri .= '/' unless $dir_uri =~ m:/$:;
$r->log_error(sprintf("%s (%s %s): ",
(caller(0))[3], __FILE__, __LINE__),
Data::Dumper->Dump([$dir_uri], [qw(dir_uri)])) if $debug;
my $subr = $r->lookup_uri($dir_uri);
my $dir = $subr->filename;
$r->log_error(sprintf("%s (%s %s): ",
(caller(0))[3], __FILE__, __LINE__),
Data::Dumper->Dump([$dir], [qw(dir)])) if $debug;
my $dh = DirHandle->new($dir);
unless ($dh) {
$r->log_error(sprintf("%s (%s %s): ",
(caller(0))[3], __FILE__, __LINE__),
"unable to read directory '$dir': $!");
goto done;
}
my @files;
for my $entry ($dh->read) {
my $rr = $subr->lookup_uri($entry);
my $type = $rr->content_type;
next unless $type =~ m:^image/:;
push @files, $rr->uri;
}
$dh->close;
unless (scalar @files) {
$r->log_error(sprintf("%s (%s %s): ",
(caller(0))[3], __FILE__, __LINE__),
"no image files found in directory '$dir'");
goto done;
}
$r->log_error(sprintf("%s (%s %s): ",
(caller(0))[3], __FILE__, __LINE__),
Data::Dumper->Dump([EMAIL PROTECTED], [qw(*files)])) if $debug;
my $lucky_one = $files[rand scalar @files];
$r->log_error(sprintf("%s (%s %s): ",
(caller(0))[3], __FILE__, __LINE__),
Data::Dumper->Dump([$lucky_one], [qw(lucky_one)])) if $debug;
my $lucky_uri = $r->lookup_uri($lucky_one);
$r->log_error(sprintf("%s (%s %s): ",
(caller(0))[3], __FILE__, __LINE__),
Data::Dumper->Dump([$lucky_uri], [qw(lucky_uri)])) if $debug;
unless ($lucky_uri->status == DOCUMENT_FOLLOWS) {
$r->log_error(sprintf("%s (%s %s): ",
(caller(0))[3], __FILE__, __LINE__),
"error looking up URI '$lucky_one'");
goto done;
}
$r->content_type($lucky_uri->content_type);
if ($r->header_only) {
$r->send_http_header;
}
else {
my %err_headers_out = $r->err_headers_out;
$r->log_error(sprintf("%s (%s %s): ",
(caller(0))[3], __FILE__, __LINE__),
Data::Dumper->Dump([\%err_headers_out],
[qw(err_headers_out)])) if $debug;
##### After much pain and suffering, these are the headers needed for
##### IE 6.0 SP2 to display the picture Apache was sending, rather than
##### using it's cache. The clue came from here:
##### http://www.phpbuilder.com/tips/item.php?id=123
##### This one doesn't seem to be necessary.
# $r->err_header_out("Expires" => 0);
##### Subrequest will send a "Last-Modified" header per the document
##### date/time stamp. Commenting this out causes IE to cache. I
##### guess IE uses the most recent of the two headers (?), so we
##### need this:
$r->err_header_out("Last-Modified" => time());
##### err_header_out() doesn't seem to accept multiple values for the
##### same header (I tried an array ref; no luck). Subsequent calls
##### step on the value (scalar) set by previous calls. The first
##### header alone doesn't work. The second and third headers alone
##### seem to stop caching. Use the third one.
# $r->err_header_out("Cache-control"=>"no-cache");
# $r->err_header_out("Cache-control"=>"post-check=0,pre-check=0");
$r->err_header_out("Cache-control"=>"max-age=0");
##### This one doesn't seem to be necessary.
# $r->err_header_out("Pragma" => "no-cache");
%err_headers_out = $r->err_headers_out;
$r->log_error(sprintf("%s (%s %s): ",
(caller(0))[3], __FILE__, __LINE__),
Data::Dumper->Dump([\%err_headers_out],
[qw(err_headers_out)])) if $debug;
$r->internal_redirect($lucky_one);
}
$retval = OK;
done:
$r->log_error(sprintf("%s (%s %s): ",
(caller(0))[3], __FILE__, __LINE__),
Data::Dumper->Dump([$retval], [qw(retval)])) if $debug;
return $retval;
}
#######################################################################
# end of code:
#----------------------------------------------------------------------
1;
__END__
#######################################################################