Django

Code

Ticket #5791 (closed: fixed)

Opened 2 years ago

Last modified 11 months ago

Conditional get decorator

Reported by: Maniac@SoftwareManiacs.Org Assigned to: nobody
Milestone: Component: HTTP handling
Version: SVN Keywords:
Cc: simon@akoha.com Triage Stage: Accepted
Has patch: 1 Needs documentation: 0
Needs tests: 0 Patch needs improvement: 0

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

5791.diff (9.6 kB) - added by Maniac@SoftwareManiacs.Org on 10/21/07 18:21:42.
Patch
5791.2.diff (12.8 kB) - added by isagalaev on 07/13/08 16:28:25.
Patch updated to current trunk + docs
5791.3.diff (12.8 kB) - added by isagalaev on 11/16/08 15:29:11.
Patch updated to current trunk + new docs structure
5791.4.diff (12.9 kB) - added by isagalaev on 12/06/08 06:50:07.
Patch updated to current trunk + Adrian's new docs structure
5791.5.diff (14.0 kB) - added by isagalaev on 01/03/09 06:30:45.
Patch with proper etag parsing and quoting

Change History

10/21/07 18:21:42 changed by Maniac@SoftwareManiacs.Org

  • attachment 5791.diff added.

Patch

12/02/07 18:57:20 changed by Simon G <dev@simon.net.nz>

  • needs_better_patch changed.
  • stage changed from Unreviewed to Ready for checkin.
  • needs_tests changed.
  • needs_docs changed.

06/15/08 15:23:41 changed by telenieko

  • needs_docs set to 1.
  • stage changed from Ready for checkin to Accepted.

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

06/22/08 18:46:54 changed by Ivan Sagalaev <Maniac@SoftwareManiacs.Org>

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 :-)

07/13/08 16:28:25 changed by isagalaev

  • attachment 5791.2.diff added.

Patch updated to current trunk + docs

07/13/08 16:30:58 changed by isagalaev

  • needs_docs deleted.

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.

08/14/08 17:17:29 changed by julianb

  • needs_better_patch set to 1.
  • milestone set to 1.0 maybe.

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!).

(follow-up: ↓ 7 ) 08/14/08 17:35:54 changed by isagalaev

  • needs_better_patch deleted.
  • milestone deleted.

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 ) 08/15/08 04:43:34 changed by julianb

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.

(follow-up: ↓ 9 ) 08/15/08 04:55:21 changed by isagalaev

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 ) 08/15/08 17:48:39 changed by julianb

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.

11/16/08 15:29:11 changed by isagalaev

  • attachment 5791.3.diff added.

Patch updated to current trunk + new docs structure

12/06/08 06:50:07 changed by isagalaev

  • attachment 5791.4.diff added.

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

01/02/09 15:48:57 changed by mmalone

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

01/03/09 06:29:45 changed by isagalaev

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.

01/03/09 06:30:45 changed by isagalaev

  • attachment 5791.5.diff added.

Patch with proper etag parsing and quoting

02/20/09 13:19:40 changed by sfllaw

  • cc set to simon@akoha.com.

03/22/09 02:58:30 changed by mtredinnick

  • status changed from new to closed.
  • resolution set to fixed.

(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.

03/22/09 03:00:37 changed by mtredinnick

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. :-(

03/22/09 04:57:27 changed by isagalaev

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!


Add/Change #5791 (Conditional get decorator)




Change Properties
Action