httpd-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Andrew Wilson <>
Subject NoCache && !DefaultExpires
Date Sun, 09 Jun 1996 17:43:52 GMT

	so about a week ago a patch was sent in via RobH which 
tried to set an Expires: header in the event of r->no_cache == 1.
It was remarked that:

    a) the guy could just use mod_expires.c instead (couldn't he?)
    b) did mod_expires.c have access to r->no_cache anyway?

Recall that under the present strategy Apache will see r->no_cache
== 1 and respond by *not* sending out a Last-modified: header.
The patch fixed the the problem of talking to browsers/proxies that
*didn't* understand that no Last-modified is equivalent to an Expires.

So, (a)...

You can influence the expires header for a file in several ways with
the present module set.

    i)     make a .meta file for the specific file you want to influence
           and add your own Expires header.
    ii)    make an .asis file, wherein you control all of the file's content
    iii)   use nph- scripts, again you get full control of the headers

    iv)    use mod_expires.c

Using mod_expires.c (to version 0.0.10) you can specify an
ExpiresDefault value, on a per-directory basis, which is used to
build the Expires: header for a page.  Therefore if you wanted to
add an Expires: header to r->no_cache requests then you *could*
.conf or .htaccess up something like:

--- cut here ---
# immediate expiry for all non cachable files
ExpiresDefault now
--- cut here ---

Which would issue an 'Expires: <access time stamp>' header, without
the need to hack modules or the server core.

The problem with this approach is that ExpiresDefault is meant to
be used for other purposes, ie to set more meaningful expiry time
for a directories contents:

--- cut here ---
# don't hang on to this stuff for more than a month
ExpiresDefault now plus 30 days
--- cut here ---

One situation that causes problems then is where you have a directory


Here you might want the counter page to be Expired immediately (so
that if you're using a proxy and you ask for a reload you get the
new page), and the unchanging page to be stamped for expiry after
30 days.  Right now mod_expires.c isn't flexible enough to cope
with this.  You can expire stuff immediately, or after 30 days,
but not both.

This is where you get to ask "why don't you hack on mod_expires.c
to test r->no_cache and update the Expires: header accordingly?"...

So (b)...

mod_expires.c does all it's work in fixups, ie, before the 'handler'
is invoked for the request and before the value of r->no_cache has
been set (eg before the .html file's u+x bit has been detected...).

Now, this is where you get to ask "er, why don't you use a */*
handler that just returns DECLINED, since invoke_handler(r) is
called *after* fixups(r)?"

Ok, we can do this (version 0.0.8 did in fact) and provided that
mod_expires.c is the first module to be called (or more specifically
all modules called before mod_expires return the value DECLINED)
then we can be *certain* that the mod_expires.c code is executed...

But we still aren't sure that r->no_cache won't be set in a module
that *follows* on from mod_expires.  If we mess about with the
module order in Configuration to get some 'magic order' that works
then we greatly restrict the flexibility of the server and increase
the interdependance of modules.  Not nice.

So what the heck else can a guy do?!?

Well, I tried 'ExpiresByType text/xserver-parsed-html now', which
would have been *great* if it had worked but, no luck.  Anyway it
doesn't catch 'r->no_cache == 1' situations like error pages,
redirects and the like.

So it looks likely that the best short term fix is (reading from
the source code) to do just what http_protocol.c, set_last_modified()

    /* Cacheing proxies use the absence of a Last-modified header
     * to indicate that a document is dynamic and shouldn't be cached.
     * For the moment, we enforce that here, though it would probably
     * work just as well to generate an Expires: header in send_http_header.

Since everything ends up calling send_http_header() why not just
hack that and be done with it, it'd work, even if at the expense
of having Expires: information being controlled by 2 different parts
of the server (in core and in a module).

So much for reinventing the wheel... there is another approach
which might be useful, and which might give me my long wished for
pre-send hook in the API.  That's for the next post...


View raw message