You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@httpd.apache.org by Mark Montague <ma...@catseye.org> on 2014/08/23 04:50:30 UTC
[RFC] enhancement: mod_cache bypass
I've attached a proof-of-concept patch against httpd 2.4.10 that allows
mod_cache to be bypassed under conditions specified in the conf files.
It adds an optional fourth argument to the CacheEnable directive:
CacheEnable cache_type [url-string] [expr=expression]
If the expression is present, data will only be served from the cache
for requests for which the expression evaluates to true. This permits
things such as:
# Only serve cached data if no (login or other) cookies are present in
the request:
CacheEnable disk / "expr=-z %{req:Cookie}"
# Do not serve cached pages to our testing network:
<Location /some/path>
CacheEnable disk "expr=! ( %{REMOTE_ADDR} -ipmatch
192.168.0.0/16 )"
</Location>
Is there interest in such an enhancement? If so, I'll make any
requested changes to the implementation, port the patch forward to
trunk, put in real APLOGNOs, make sure it passes the test suite, create
a documentation patch, and create a bugzilla for all this.
--
Mark Montague
mark@catseye.org
Re: [RFC] enhancement: mod_cache bypass
Posted by Mark Montague <ma...@catseye.org>.
On 2014-08-23 12:36, Graham Leggett wrote:
> On 23 Aug 2014, at 3:40 PM, Mark Montague <ma...@catseye.org> wrote:
>
>> [root@sky ~]# httpd -t
>> AH00526: Syntax error on line 148 of /etc/httpd/conf/dev.catseye.org.conf:
>> CacheEnable cannot occur within <If> section
>> [root@sky ~]#
> The solution here is to lift the restriction above. Having a generic mechanism to handle conditional behaviour, and then having a special case to handle the same behaviour in a different way is wrong way to go.
I've looked into allowing CacheEnable directives within <If> sections.
This can be done by removing the NOT_IN_FILES flag from the call to
ap_check_cmd_context() in modules/cache/mod_cache.c:add_cache_enable()
The problem is that <If> sections are currently walked only during
mod_cache's normal handler phase, not during the quick handler phase.
It looks easy enough to add a call to ap_if_walk() to
cache_quick_handler(), but this would add significant extra processing
to the quick handler phase, as all <If> expressions for the enclosing
context would be evaluated, and I think that at the end we'd have to
discard the results that ap_if_walk() caches in the request record so
that they can be recomputed later during normal request processing after
all information about the request is available. Is this acceptable?
Also, the proof of concept patch that I sent yesterday, which adds an
expr= clause to the CacheEnable directive, records cache bypasses in the
request notes (for logging), in the X-Cache and X-Cache-Detail headers,
in the cache-status subprocess environment variable, and adds a new
subprocess environment variable named cache-bypass. If we enable using
CacheEnable in <If> sections, conditional cache bypasses will no longer
be called out explicitly to the server administrator; they will need to
infer a bypass from comparing the URL path to their configuration. I do
not see this as a large problem, but I thought I would mention it for
consideration.
Given these things, what thoughts does the developer community have?
Would a patch to allow CacheEnable within <If> sections have a better
chance of being accepted than one that adds a expr= clause to the
CacheEnable directive?
Or should mod_cache not allow cache bypassing at all? "Use NGINX (
http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_cache_bypass
) if you want that" or "use Varnish (
https://www.varnish-cache.org/docs/4.0/users-guide/increasing-your-hitrate.html#cookies
) if you want that" are answers I'm fine with, if there's no interest in
this feature for httpd's mod_cache.
--
Mark Montague
mark@catseye.org
Re: [RFC] enhancement: mod_cache bypass
Posted by Mark Montague <ma...@catseye.org>.
On 2014-08-23 17:43, Mark Montague wrote:
>> > - Back-end sets response header "Cache-Control: max-age=0,
>> s-maxage=14400" so that mod_cache
>> > caches the response, but ISP caches and browser caches do not.
>> (mod_cache removes s-maxage
>> > and does not pass it upstream).
>> mod_cache shouldn’t remove any Cache-Control headers.
>
> It apparently does, although I haven't found where in the code yet. I
> would be interested to see if anyone can reproduce my experience. As
> far as I know, I don't have any configuration that would result in this.
Please ignore this part of my previous reply, I found out what was going on:
When the content is first requested, mod_cache has a miss and it stores
the content. But when it sends it on to the client, it does so without
any Cache-control header at all:
GET /test.php HTTP/1.1
Host: dev.catseye.org
HTTP/1.1 200 OK
Date: Sat, 23 Aug 2014 22:01:26 GMT
Server: Apache/2.4
X-Cache: MISS from dev.catseye.org
X-Cache-Detail: "cache miss: attempting entity save" from dev.catseye.org
Transfer-Encoding: chunked
Content-Type: text/html;charset=UTF-8
The second time the resource was requested, it is served by mod_cache
from the cache with the original Cache-Control header (I added "foo=1"
to the header track this when I generated the page):
GET /test.php HTTP/1.1
Host: dev.catseye.org
HTTP/1.1 200 OK
Date: Sat, 23 Aug 2014 22:02:21 GMT
Server: Apache/2.4
Cache-Control: max-age=0, foo=1, s-maxage=14400
Content-Security-Policy: default-src 'self'; script-src 'self'
'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src
'self' data: ; font-src 'self' data: ; report-uri /csp-report.php
Age: 54
X-Cache: HIT from dev.catseye.org
X-Cache-Detail: "cache hit" from dev.catseye.org
Content-Length: 33
Content-Type: text/html;charset=UTF-8
What was happening was that led me to assume that mod_cache was
"editing" the header (which, I now see, it wasn't) was because I had the
following directives that escaped my attention when I was composing my
previous reply:
ExpiresActive on
ExpiresDefault "access plus 1 week"
ExpiresByType text/html "access plus 0 seconds"
This resulted in a "Cache-control: max-age=0" header being
unconditionally added to the response headers, even if another header
was already there. So for a cache miss, I would see:
Cache-control: max-age=0
while for a cache hit I would see
Cache-control: max-age=0
Cache-Control: max-age=0, foo=1, s-maxage=14400
Mystery solved. I apologize for the red herring and waste of people's
time and attention.
I'm still looking for a solution to the original problem: how to
indicate to mod_cache that cached content for a particular URL path
should be served to some clients (ones without login cookies), but not
to other clients (ones with login cookies).
--
Mark Montague
mark@catseye.org
Re: [RFC] enhancement: mod_cache bypass
Posted by Mark Montague <ma...@catseye.org>.
On 2014-08-23 12:36, Graham Leggett wrote:
> On 23 Aug 2014, at 3:40 PM, Mark Montague <ma...@catseye.org> wrote:
>
>> AH00526: Syntax error on line 148 of
>> /etc/httpd/conf/dev.catseye.org.conf: CacheEnable cannot occur within
>> <If> section
> The solution here is to lift the restriction above. Having a generic mechanism to handle conditional behaviour, and then having a special case to handle the same behaviour in a different way is wrong way to go.
I assumed this would be OK because the Header directive has a similar
expr=expression clause.
But, I'll look into whether if restriction on If could be removed. If I
rewrite things to use the If directive, do you see bypass functionality
as something worth including? I ask because from your points below I
get the impression that the answer is "no".
>> The proposed enhancement is about the server deciding when to serve items from the cache. Although the client can specify a Cache-Control request header in order to bypass the server's cache, there is no good way for a web application to signal to a client when it should do this (for example., when a login cookie is set). The behavior of other caches is controlled using the Cache-Control response header.
> There is - use “Cache-Control: private”. This will tell all public caches, including mod_cache and ISP caches, not to cache content with cookies attached, while at the same time telling browser caches that they should.
The problem is not whether the content should be cached: it should.
The problem is, to which clients should the cached content be served?
If the client's request does not contain a login cookie, that client
should get the cached copy. If the client's request does contain a
login cookie, the cache should be bypassed and the client should get a
copy of the resource generated specifically for it.
"Cache-Control: private" cannot be used in a request, only in a
response, where it works as you said. The problem is that the first
request for a given resource where the client includes a login cookie
gets intercepted by mod_cache and served from the cache (if you assume
that other clients without login cookies have already requested it).
There must therefore be some way to tell mod_cache that this client
needs something different. One way to do this would be by having
different URL paths for logged in versus non-logged in users, but this
is awkward, user-visible, and may not be feasible with all web application.
> > - Back-end sets response header "Cache-Control: max-age=0, s-maxage=14400" so that mod_cache
> > caches the response, but ISP caches and browser caches do not. (mod_cache removes s-maxage
> > and does not pass it upstream).
> mod_cache shouldn’t remove any Cache-Control headers.
It apparently does, although I haven't found where in the code yet. I
would be interested to see if anyone can reproduce my experience. As far
as I know, I don't have any configuration that would result in this.
httpd 2.4.10 with mod_proxy_fcgi (Fedora 19 build)
PHP 5.5.5 with PHP-FPM
Relevant configuration:
CacheEnable disk /
CacheDefaultExpire 86400
CacheIgnoreHeaders Set-Cookie
CacheHeader on
CacheDetailHeader on
# We'll be paying attention to "Cache-Control: s-maxage=xxx" for all
# of our caching decisions. The browser will use max-age=yyy for its
# decisions. So we drop the Expires header. See the following page
# from Google which says, "It is redundant to specify both Expires and
# Cache-Control: max-age"
# https://developers.google.com/speed/docs/best-practices/caching?hl=sv
Header unset Expires
RewriteRule ^(.*\.php)$
fcgi://127.0.0.1:9001/www/dev.catseye.org/content/$1 [P,L]
File test.php, containing:
<?php
header( "Cache-Control: max-age=0, s-maxage=14400" );
header( "Content-type: text/html" );
?>
<html><body>Hello!</body></html>
Browser transaction for https://dev.catseye.org/test.php:
GET /test.php HTTP/1.1
Host: dev.catseye.org
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:31.0)
Gecko/20100101 Firefox/31.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
DNT: 1
Connection: keep-alive
HTTP/1.1 200 OK
Date: Sat, 23 Aug 2014 20:11:00 GMT
Server: Apache/2.4
Cache-Control: max-age=0
X-Cache: MISS from dev.catseye.org
X-Cache-Detail: "cache miss: attempting entity save" from dev.catseye.org
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: text/html;charset=UTF-8
And mod_cache definitely receives s-maxage from the backend:
[root@sky cache]# cat ./J/k/WPiKG0bwW@R_H4YvSOdw.header
(binary data omitted)https://dev.catseye.org:443/test.php?Cache-Control:
max-age=0
Cache-Control: max-age=0, s-maxage=14400
Content-Security-Policy: default-src 'self'; script-src 'self'
'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src
'self' data: ; font-src 'self' data: ; report-uri /csp-report.php
Content-Type: text/html;charset=UTF-8
Host: dev.catseye.org
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:31.0)
Gecko/20100101 Firefox/31.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
DNT: 1
[root@sky cache]# cat ./J/k/WPiKG0bwW@R_H4YvSOdw.data
<html><body>Hello!</body></html>
[root@sky cache]#
>> - When back-end content changes (e.g., an author makes an update), the back-end invokes "htcacheclean /path/to/resource" to invalidate the cached page so that it is regenerated the next time a client requests it.
> Set your max-age correctly and this becomes unnecessary. If you have long lived resources that you want caching for a very long time, and you want to change that resource, place the version number of the resource in the URL and refer to the new URL after the change.
This is fine for JavaScript, CSS files, and images, but I'd rather have
users see nice, human-friendly URLs in their browsers location bar, like
https://example.com/latest-news
Rather than
https://example.com/latest-news?20140823T164300
...and I certainly don't want them bookmarking the latter one.
>> - Clients have multiple cookies set. Tracking cookies and cookies used by JavaScript should not cause a mod_cache miss.
>> - Dynamic pages that are generated when a login cookie is set should not be cached. This is accomplished by the back-end setting the response header "Cache-Control: max-age=0”.
> This is incorrect, max-age=0 means that a cache is welcome to cache the content, but the content must be declared stale immediately and revalidated.
I checked the code and what is actually getting set for all pages
dynamically generated for logged-in users is:
Cache-Control: no-cache, must-revalidate, max-age=0
I apologize for being sloppy and not verifying this before sending my
previous reply.
>> - However, when a login cookie is set, dynamic pages that are currently cached should not be served to the client with the login cookie, while they should still be served to all other clients.
> All of the above is handled by HTTP already, just follow the protocol.
>
> Make sure you separate your cacheable content from your uncacheable content. Ensure that you use HTTP conditional requests so that expensive calls can be made cheap. Properly declare the request headers you vary on using the Vary header, but keep in mind that headers with many variations will DoS a cache. Cache long-lived content and change the URL if the content is updated. Use max-age (and s-maxage) on short lived content to make the generation of it cheap.
The only thing I see above that will actually help is having separate
URL paths for cachable and non-cachable content, but I'd have to hack
that in using mod_rewrite (since I'm limited to the scope of changes I
can make to the code of 3rd party web applications). I'd prefer to
avoid having logged in and non-logged in users seeing different URLs in
their browser location bars.
Thanks for all of your replies!
--
Mark Montague
mark@catseye.org
Re: [RFC] enhancement: mod_cache bypass
Posted by Graham Leggett <mi...@sharp.fm>.
On 23 Aug 2014, at 3:40 PM, Mark Montague <ma...@catseye.org> wrote:
>> Does this not duplicate the functionality of the If directives?
>
> No, not in this case:
>
> <If "-z %{req:Cookie}">
> CacheEnable disk /
> </If>
>
> [root@sky ~]# httpd -t
> AH00526: Syntax error on line 148 of /etc/httpd/conf/dev.catseye.org.conf:
> CacheEnable cannot occur within <If> section
> [root@sky ~]#
>
> Also, any solution has to work within both the quick handler phase and the normal handler phase of mod_cache.
The solution here is to lift the restriction above. Having a generic mechanism to handle conditional behaviour, and then having a special case to handle the same behaviour in a different way is wrong way to go.
> The proposed enhancement is about the server deciding when to serve items from the cache. Although the client can specify a Cache-Control request header in order to bypass the server's cache, there is no good way for a web application to signal to a client when it should do this (for example., when a login cookie is set). The behavior of other caches is controlled using the Cache-Control response header.
There is - use “Cache-Control: private”. This will tell all public caches, including mod_cache and ISP caches, not to cache content with cookies attached, while at the same time telling browser caches that they should.
> Here is a more detailed example scenario, in case it helps. There are also many other scenarios in which conditionally bypassing mod_cache is useful.
>
> - Reverse proxy setup using mod_proxy_fcgi
> - Static resources served through httpd front-end with response header "Cache-Control: max-age=14400" so that they are cached by mod_cache, ISP caches, and browser caches.
> - Back-end pages are dynamic (PHP), but very expensive to generate (1-2 seconds).
> - Back-end sets response header "Cache-Control: max-age=0, s-maxage=14400" so that mod_cache caches the response, but ISP caches and browser caches do not. (mod_cache removes s-maxage and does not pass it upstream).
mod_cache shouldn’t remove any Cache-Control headers.
> - When back-end content changes (e.g., an author makes an update), the back-end invokes "htcacheclean /path/to/resource" to invalidate the cached page so that it is regenerated the next time a client requests it.
Set your max-age correctly and this becomes unnecessary. If you have long lived resources that you want caching for a very long time, and you want to change that resource, place the version number of the resource in the URL and refer to the new URL after the change.
> - Clients have multiple cookies set. Tracking cookies and cookies used by JavaScript should not cause a mod_cache miss.
> - Dynamic pages that are generated when a login cookie is set should not be cached. This is accomplished by the back-end setting the response header "Cache-Control: max-age=0”.
This is incorrect, max-age=0 means that a cache is welcome to cache the content, but the content must be declared stale immediately and revalidated.
> - However, when a login cookie is set, dynamic pages that are currently cached should not be served to the client with the login cookie, while they should still be served to all other clients.
All of the above is handled by HTTP already, just follow the protocol.
Make sure you separate your cacheable content from your uncacheable content. Ensure that you use HTTP conditional requests so that expensive calls can be made cheap. Properly declare the request headers you vary on using the Vary header, but keep in mind that headers with many variations will DoS a cache. Cache long-lived content and change the URL if the content is updated. Use max-age (and s-maxage) on short lived content to make the generation of it cheap.
Regards,
Graham
—
Re: [RFC] enhancement: mod_cache bypass
Posted by Tim Bannister <is...@jellybaby.net>.
On 23 August 2014 14:40:36 GMT+01:00, Mark Montague <ma...@catseye.org> wrote:
>On 2014-08-23 5:19, Graham Leggett wrote:
>> On 23 Aug 2014, at 03:50, Mark Montague <mark@catseye.org
>> <ma...@catseye.org>> wrote:
>>
>>> I've attached a proof-of-concept patch against httpd 2.4.10 that
>>> allows mod_cache to be bypassed under conditions specified in the
>>> conf files.
>>
>> Does this not duplicate the functionality of the If directives?
>
>No, not in this case:
>
><If "-z %{req:Cookie}">
> CacheEnable disk /
></If>
>
>[root@sky ~]# httpd -t
>AH00526: Syntax error on line 148 of
>/etc/httpd/conf/dev.catseye.org.conf:
>CacheEnable cannot occur within <If> section
>[root@sky ~]#
>
>Also, any solution has to work within both the quick handler phase and
>the normal handler phase of mod_cache.
>
>
>>> # Only serve cached data if no (login or other) cookies are present
>>> in the request:
>>> CacheEnable disk / "expr=-z %{req:Cookie}"
>>
>> As an aside, trying to single out and control just one cache using
>> directives like this is ineffective, as other caches like ISP caches
>> and browser caches will not be included in the configuration.
>>
>> Rather control the cache using the Cache-Control headers in the
>formal
>> HTTP specs.
>
>The proposed enhancement is about the server deciding when to serve
>items from the cache. Although the client can specify a Cache-Control
>request header in order to bypass the server's cache, there is no good
>way for a web application to signal to a client when it should do this
>(for example., when a login cookie is set). The behavior of other
>caches
>is controlled using the Cache-Control response header.
>
>This functionality is provided by Varnish Cache:
>https://www.varnish-cache.org/docs/4.0/users-guide/increasing-your-hitrate.html#cookies
>
>Squid does not currently provide this functionality, but it seems like
>there is consensus that it should:
>http://bugs.squid-cache.org/show_bug.cgi?id=2258
>
>Here is a more detailed example scenario, in case it helps. There are
>also many other scenarios in which conditionally bypassing mod_cache is
>
>useful.
>
>- Reverse proxy setup using mod_proxy_fcgi
>- Static resources served through httpd front-end with response header
>"Cache-Control: max-age=14400" so that they are cached by mod_cache,
>ISP
>caches, and browser caches.
>- Back-end pages are dynamic (PHP), but very expensive to generate (1-2
>
>seconds).
>- Back-end sets response header "Cache-Control: max-age=0,
>s-maxage=14400" so that mod_cache caches the response, but ISP caches
>and browser caches do not. (mod_cache removes s-maxage and does not
>pass it upstream).
>- When back-end content changes (e.g., an author makes an update), the
>back-end invokes "htcacheclean /path/to/resource" to invalidate the
>cached page so that it is regenerated the next time a client requests
>it.
>- Clients have multiple cookies set. Tracking cookies and cookies used
>
>by JavaScript should not cause a mod_cache miss.
>- Dynamic pages that are generated when a login cookie is set should
>not
>be cached. This is accomplished by the back-end setting the response
>header "Cache-Control: max-age=0".
>- However, when a login cookie is set, dynamic pages that are currently
>
>cached should not be served to the client with the login cookie, while
>they should still be served to all other clients.
A web application can and should use
Cache-Control: private
or
Vary:
headers on its responses, to avoid having them be incorrectly served from a shared cache.
I can see a case for webapps having better control over invalidation but I wouldn't do it like this.
If there's still demand, why not arrange for CacheEnable to be valid within <If>?
Tim
--
Tim Bannister – isoma@jellybaby.net
Re: [RFC] enhancement: mod_cache bypass
Posted by Mark Montague <ma...@catseye.org>.
On 2014-08-23 5:19, Graham Leggett wrote:
> On 23 Aug 2014, at 03:50, Mark Montague <mark@catseye.org
> <ma...@catseye.org>> wrote:
>
>> I've attached a proof-of-concept patch against httpd 2.4.10 that
>> allows mod_cache to be bypassed under conditions specified in the
>> conf files.
>
> Does this not duplicate the functionality of the If directives?
No, not in this case:
<If "-z %{req:Cookie}">
CacheEnable disk /
</If>
[root@sky ~]# httpd -t
AH00526: Syntax error on line 148 of /etc/httpd/conf/dev.catseye.org.conf:
CacheEnable cannot occur within <If> section
[root@sky ~]#
Also, any solution has to work within both the quick handler phase and
the normal handler phase of mod_cache.
>> # Only serve cached data if no (login or other) cookies are present
>> in the request:
>> CacheEnable disk / "expr=-z %{req:Cookie}"
>
> As an aside, trying to single out and control just one cache using
> directives like this is ineffective, as other caches like ISP caches
> and browser caches will not be included in the configuration.
>
> Rather control the cache using the Cache-Control headers in the formal
> HTTP specs.
The proposed enhancement is about the server deciding when to serve
items from the cache. Although the client can specify a Cache-Control
request header in order to bypass the server's cache, there is no good
way for a web application to signal to a client when it should do this
(for example., when a login cookie is set). The behavior of other caches
is controlled using the Cache-Control response header.
This functionality is provided by Varnish Cache:
https://www.varnish-cache.org/docs/4.0/users-guide/increasing-your-hitrate.html#cookies
Squid does not currently provide this functionality, but it seems like
there is consensus that it should:
http://bugs.squid-cache.org/show_bug.cgi?id=2258
Here is a more detailed example scenario, in case it helps. There are
also many other scenarios in which conditionally bypassing mod_cache is
useful.
- Reverse proxy setup using mod_proxy_fcgi
- Static resources served through httpd front-end with response header
"Cache-Control: max-age=14400" so that they are cached by mod_cache, ISP
caches, and browser caches.
- Back-end pages are dynamic (PHP), but very expensive to generate (1-2
seconds).
- Back-end sets response header "Cache-Control: max-age=0,
s-maxage=14400" so that mod_cache caches the response, but ISP caches
and browser caches do not. (mod_cache removes s-maxage and does not
pass it upstream).
- When back-end content changes (e.g., an author makes an update), the
back-end invokes "htcacheclean /path/to/resource" to invalidate the
cached page so that it is regenerated the next time a client requests it.
- Clients have multiple cookies set. Tracking cookies and cookies used
by JavaScript should not cause a mod_cache miss.
- Dynamic pages that are generated when a login cookie is set should not
be cached. This is accomplished by the back-end setting the response
header "Cache-Control: max-age=0".
- However, when a login cookie is set, dynamic pages that are currently
cached should not be served to the client with the login cookie, while
they should still be served to all other clients.
--
Mark Montague
mark@catseye.org
Re: [RFC] enhancement: mod_cache bypass
Posted by Graham Leggett <mi...@sharp.fm>.
On 23 Aug 2014, at 03:50, Mark Montague <ma...@catseye.org> wrote:
> I've attached a proof-of-concept patch against httpd 2.4.10 that allows mod_cache to be bypassed under conditions specified in the conf files. It adds an optional fourth argument to the CacheEnable directive:
>
> CacheEnable cache_type [url-string] [expr=expression]
>
> If the expression is present, data will only be served from the cache for requests for which the expression evaluates to true. This permits things such as:
Does this not duplicate the functionality of the If directives?
http://httpd.apache.org/docs/current/mod/core.html#if
> # Only serve cached data if no (login or other) cookies are present in the request:
> CacheEnable disk / "expr=-z %{req:Cookie}"
As an aside, trying to single out and control just one cache using directives like this is ineffective, as other caches like ISP caches and browser caches will not be included in the configuration.
Rather control the cache using the Cache-Control headers in the formal HTTP specs.
Regards,
Graham
--