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__

#######################################################################

Reply via email to