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__ #######################################################################