Opened 17 years ago

Closed 16 years ago

Last modified 16 years ago

#5791 closed (fixed)

Conditional get decorator

Reported by: Maniac@… Owned by: nobody
Component: HTTP handling Version: dev
Severity: Keywords:
Cc: simon@… Triage Stage: Accepted
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

A view decorator taking as a parameter a function calculating Last-Modified and/or ETag that takes care of all
the mechanic of checking request headers, returning 304 Not Modified and setting response headers.

More discussion: http://groups.google.com/group/django-developers/t/fa6c36efde4cf106

Attachments (5)

5791.diff (9.6 KB ) - added by Maniac@… 17 years ago.
Patch
5791.2.diff (12.8 KB ) - added by Ivan Sagalaev 16 years ago.
Patch updated to current trunk + docs
5791.3.diff (12.8 KB ) - added by Ivan Sagalaev 16 years ago.
Patch updated to current trunk + new docs structure
5791.4.diff (12.9 KB ) - added by Ivan Sagalaev 16 years ago.
Patch updated to current trunk + Adrian's new docs structure
5791.5.diff (14.0 KB ) - added by Ivan Sagalaev 16 years ago.
Patch with proper etag parsing and quoting

Download all attachments as: .zip

Change History (20)

by Maniac@…, 17 years ago

Attachment: 5791.diff added

Patch

comment:1 by Simon G <dev@…>, 17 years ago

Triage Stage: UnreviewedReady for checkin

comment:2 by Marc Fargas, 16 years ago

Needs documentation: set
Triage Stage: Ready for checkinAccepted

Maybe I got it wrong, but should this add documentation?

comment:3 by Ivan Sagalaev <Maniac@…>, 16 years ago

Sure it's better to have docs than not to have :-). The main reason why I was lazy with it is that existing decorators (require_POST et al.) also don't have docs so I couldn't completely figure out where to put it. But I'll do it now if it helps to commit it :-)

by Ivan Sagalaev, 16 years ago

Attachment: 5791.2.diff added

Patch updated to current trunk + docs

comment:4 by Ivan Sagalaev, 16 years ago

Needs documentation: unset

I've updated the patch to apply to current trunk and wrote some docs. The patch is now a bit easier to review (I've thrown out some scary looking memoizations). Docs require proof-reading, of course, English is not my native tongue.

comment:5 by Julian Bez, 16 years ago

milestone: 1.0 maybe
Patch needs improvement: set

Strangely, I don't see a patch when I follow the link. Does it include "returning 304 Not Modified and setting response headers"? Would be better if that's handled by ConditionalGetMiddleware (DRY!).

comment:6 by Ivan Sagalaev, 16 years ago

milestone: 1.0 maybe
Patch needs improvement: unset

Strangely, I don't see a patch when I follow the link.

I gather this is a bug in Trac. You can still see the patch be following the "Original format" link there.

Does it include "returning 304 Not Modified and setting response headers"?

Sure, it's the whole point of conditional get :-)

Would be better if that's handled by ConditionalGetMiddleware (DRY!)

A middleware by definition can't handle it the way the patch does. It enables generation of last modified times and etags on a per-view basis using application specific semantics.

P.S. Please don't alter flags like "Patch needs improvement" unless you're a Django triager/comitter and especially even if you didn't read it.

in reply to:  6 comment:7 by Julian Bez, 16 years ago

Replying to isagalaev:

A middleware by definition can't handle it the way the patch does. It enables generation of last modified times and etags on a per-view basis using application specific semantics.

I was talking about the evaluation of Last-Modified and etag headers and returning 304 if there was no change, so that is the task of the middleware and should not be included here again. The middleware handles that beautifully afaik.

comment:8 by Ivan Sagalaev, 16 years ago

Ah, I've got what you mean.
I don't think it should be delegated to middleware because it'll make it more complex to use: it requires two middlewares in settings apart from just importing a decorator and use it. It's also not very obvious. And, frankly, code reuse that we're talking about here is both small -- returning a HttpResponseNotModified with Last-Modified and ETag -- and hard -- inventing a way to tell middleware to do something without returning a response because not generating a response is the point of this decorator. So I wouldn't bother...

in reply to:  8 comment:9 by Julian Bez, 16 years ago

Ah, now I've got what you mean ;)

Unless there's a way to invoke the ConditionalGetMiddleware in the middle of what you patch does, it's really better to not bother.

by Ivan Sagalaev, 16 years ago

Attachment: 5791.3.diff added

Patch updated to current trunk + new docs structure

by Ivan Sagalaev, 16 years ago

Attachment: 5791.4.diff added

Patch updated to current trunk + Adrian's new docs structure

comment:10 by Michael Malone, 16 years ago

There's a (rather trivial) bug in the latest patch. According to the HTTP spec, ETags are opaque strings. The only requirement is that they must be quoted. The current diff does a simple split on the comma character, but this breaks things if the ETag contains a comma. I'd submit a new diff and add a test, but I don't have a django dev environment setup at the moment. The fix should be simple enough, instead of doing:

if_none_match = [e.strip() for e in if_none_match.split(',')]

do this:

if_none_match = re.findall('(?:W/)?"[^"]*"', if_none_match)

Note that there's no check that the quoted strings are comma-separated. I think that's ok -- the spec says they have to be comma separated, and if they're not then the result is undefined. Relevant spec info is here:

http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.11

comment:11 by Ivan Sagalaev, 16 years ago

Thanks for the pointer! Indeed, I've missed that the string must be quoted. They are also \-escaped so I've gone further and implemented proper parsing of etags from If-None-Match and If-Match, along with proper quoting of a user-supplied string for the response ETag header. Patch with updated code and tests (5791.5.diff) follows.

by Ivan Sagalaev, 16 years ago

Attachment: 5791.5.diff added

Patch with proper etag parsing and quoting

comment:12 by Simon Law, 16 years ago

Cc: simon@… added

comment:13 by Malcolm Tredinnick, 16 years ago

Resolution: fixed
Status: newclosed

(In [10114]) Fixed #5791 -- Added early-bailout support for views (ETags and Last-modified).

This provides support for views that can have their ETag and/or Last-modified
values computed much more quickly than the view itself. Supports all HTTP
verbs (not just GET).

Documentation and tests need a little more fleshing out (I'm not happy with the
documentation at the moment, since it's a bit backwards), but the functionality
is correct.

comment:14 by Malcolm Tredinnick, 16 years ago

Oh, sorry Ivan. I completely forgot to give you credit for all the heavy-lifting in the commit message. I'm getting too tired. Really sorry about that. :-(

comment:15 by Ivan Sagalaev, 16 years ago

Malcolm, it's no a problem! I'll just blog about it and have my share of fame anyway :-)

A big thank you for doing it for 1.1!

Note: See TracTickets for help on using tickets.
Back to Top