never_cache and firefox

66 views
Skip to first unread message

davathar

unread,
Mar 3, 2009, 4:48:59 PM3/3/09
to Django users
I'm using @never_cache as follows and IE7 has the correct behavior,
but Firefox 3.06 allows me to view the content of all previous pages
by clicking the back button even after going through a logout.

@never_cache
@login_required()
def search(request, search):


Gmail has the correct behavior in firefox and IE and it's response
headers look like this:

Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: Fri, 01 Jan 1990 00:00:00 GMT
Date: Tue, 03 Mar 2009 20:14:58 GMT
Content-Type: text/html; charset=UTF-8
Set-Cookie: GMAIL_IMP=EXPIRED; Expires=Mon, 02-Mar-2009 20:14:58 GMT;
Path=/mail
Content-Encoding: gzip
Transfer-Encoding: chunked
X-Content-Type-Options: nosniff
Server: GFE/1.3


The headers I'm getting from my Django app are as follows. And as you
can tell, they are missing a lot of the stuff that Gmail seems to use
to stop caching.

Date: Tue, 03 Mar 2009 21:12:04 GMT
Server: Apache/2.2.9 (Win32) DAV/2 mod_ssl/2.2.9 OpenSSL/0.9.8h
mod_autoindex_color mod_python/3.3.1 Python/2.5.2 PHP/5.2.6
Expires: Tue, 03 Mar 2009 21:12:04 GMT
Vary: Cookie
Last-Modified: Tue, 03 Mar 2009 21:12:04 GMT
Etag: "1710a9ec54f25e5074e4decf99697a44"
Cache-Control: max-age=0
Content-Type: text/html; charset=utf-8
Connection: close
Transfer-Encoding: chunked



I've read a lot of responses on this topic. Perhaps I missed one that
works. Here are the ones I can't accept.

"This is a browser issue, nothing can be done" - Maybe it's a browser
issue, but other sites manage it, see Gmail.

"Make the user close the browser" - Relying on users to do anything
is a last resort. It may be good for them to close the browser. But
making that the only reliable solution is not good enough.

"Use Javascript to clear the cache or some other trick" - Relying on
JS being active is like relying on users.

So, is this a feature waiting to be developed? Or is there a way to
make it work right with the existing code?


Alex Gaynor

unread,
Mar 3, 2009, 6:01:19 PM3/3/09
to django...@googlegroups.com
The most obvious difference, to me, is the must-revalidate bit in the Cache-Control header.  While nothing is built into django to handle this, you are more then welcome to set the header, and create a decorator, to do this, for whicheve rheader it is.

Alex

--
"I disapprove of what you say, but I will defend to the death your right to say it." --Voltaire
"The people's good is the highest law."--Cicero

Malcolm Tredinnick

unread,
Mar 3, 2009, 8:01:54 PM3/3/09
to django...@googlegroups.com
On Tue, 2009-03-03 at 13:48 -0800, davathar wrote:
> I'm using @never_cache as follows and IE7 has the correct behavior,
> but Firefox 3.06 allows me to view the content of all previous pages
> by clicking the back button even after going through a logout.

[....]


> So, is this a feature waiting to be developed? Or is there a way to
> make it work right with the existing code?

Django does a reasonable, but not sterling, job in this particular case.
We need to add a few more "no really, we seriously mean it" headers for
the don't cache situation. The GMail instance is closer to the real
thing for never caching.

Right now Django is serving up "never_cache" as "always stale", however
browsers and intermediate caches are permitted to serve stale instance
under certain circumstances (and, when you throw in buggy
implementations, even more often than that). You're seeing the
variations of interpretation between your IE and Firefox experiments,
for example. It's a difficult area and not particularly well (and
definitely not consistently) implemented across browsers. I suspect it
might be provable that, in this case, both browsers are doing a correct
thing, if you look hard enough at the specs (particularly when you throw
in offline browsing considerations).

In conclusiong, though, we can and will, at some point, throw in a few
more headers in this particular case.

Regards,
Malcolm


davathar

unread,
Mar 3, 2009, 8:48:44 PM3/3/09
to Django users
Thank you both for your responses. I don't know if you could tell,
but I was a bit frustrated by the prior discussions on this not really
addressing the root of the problem. I'm glad to know I'm not *just*
crazy or overly picky.

In the mean time I'll try to write a wrapper for the current
functionality and I'll share it here if I'm successful. I'm new to
OOP and Django and not really all that great at programming anyway.
But I'll see what I can figure out.

Thanks,
Shane

On Mar 3, 7:01 pm, Malcolm Tredinnick <malc...@pointy-stick.com>
wrote:

davathar

unread,
Mar 3, 2009, 9:20:56 PM3/3/09
to Django users
Ok, so I'm sure that I violated DRY and probably a few other good
programming principles, but here's what I did that worked and doesn't
alter the source. It's a hack, but I'm still learning.

I created a new monkey_patches.py file and copied the function from
the core file and altered it. Now I just call @really_never_cache
instead.

try:
from functools import wraps
except ImportError:
from django.utils.functional import wraps # Python 2.3, 2.4
fallback.

from django.utils.decorators import decorator_from_middleware
from django.utils.cache import patch_cache_control,
add_never_cache_headers
from django.middleware.cache import CacheMiddleware

def really_never_cache(view_func):
"""
Replacement Decorator for never_cache that adds a few more headers
to a response so that it will never be cached.
"""
def _wrapped_view_func(request, *args, **kwargs):
response = view_func(request, *args, **kwargs)
add_never_cache_headers(response)
response['Expires'] = 'Fri, 01 Jan 1990 00:00:00 GMT'
response['Pragma'] = 'no-cache'
response['Cache-Control'] = 'no-cache, no-store, max-age=0,
must-revalidate'
return response
return wraps(view_func)(_wrapped_view_func)

Ricardo Newbery

unread,
Mar 4, 2009, 12:09:01 AM3/4/09
to django...@googlegroups.com

Note that "no-store" or "no-cache" in combination with HTTPS is known
to be buggy in some IE browsers, primarily for file downloads. If a
non-buggy HTTPS is desired, you should be able to get nearly the same
non-caching result with "max-age=0, private, must-revalidate".

'max-age=0' means cached entries are always stale.

'private' means it will never get stored in conforming shared caches
-- essentially equivalent to 'no-store' for shared caches. HTTPS-only
gives the same result.

'must-revalidate' in this case means that conforming browsers must
always revalidate stale entries which theoretically should mean a new
fresh request with each display (a conditional request if Last-
Modified or Etag is also set), although I haven't tested this behavior
with Firefox history browsing using the back button.

Note, if you're using the Firebug extension, you might want to turn it
off when testing browser cache revalidate behavior as it messes with
some of this.

Ric


Reply all
Reply to author
Forward
0 new messages