Opened 3 years ago

Closed 3 years ago

Last modified 3 years ago

#19604 closed Bug (invalid)

Bug in conditional decorator for sub-second time intervals

Reported by: anonymous Owned by: aaugustin
Component: HTTP handling Version: 1.5-beta-1
Severity: Normal Keywords:
Cc: Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no


There is a flaw in the design of the conditional decorator, when using the Last-Modified functionality, that can cause the server to mistakenly report that a resource has not been modified, when in fact it has been.

Let's use the example from the documentation of a Blog having the last-modified time be based on the publication time of the latest Blog Entry.

Publication times of blog entries, when stored in the database have millisecond precision. But the Last-Modified HTTP header has only second level precision.

Here is the scenario:

  1. The system clock of the server is currently at 10:00:01.100
  1. A client requests the "front_page" view and gets a Last-Modified time of "10:00:01" (notice the milliseconds get truncated off)
  1. Immediately after the request finishes, a new entry is published to the blog, and its publication time is set to the current time, which is now: "10:00:01.600" (notice it is still in the current second)
  1. Some time later(possibly even much later), the client requests the "front_page" view, this time with an "If-Modified-Since" header with the value that it previously received of "10:00:01".
  1. The server mistakenly returns a 304 Not Modified status code, because the new blog entry's publication time.

This may appear to be an extremely rare set of circumstances, but it can happen in practice if the client is doing very frequent polling. When it happens, the client will never find out about the new blog entry, even after the initial second is over, and possibly much longer into the future (until a new blog entry is published).

The solution: The client should ignore the "Last-Modified" header, and instead save "Date" header that is returned. (The server logic must now consider the resource modified in the case of If-Modified-Since == Last-Modified)

Due to this issue, the "Last-Modified" server header is useless and dangerous, and therefore the conditional decorator should not send it. It should instead send the "Date" header, which can actually be used correctly by the client.

Change History (3)

comment:1 Changed 3 years ago by akaariai

  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset
  • Triage Stage changed from Unreviewed to Accepted

Seems like a possible condition to hit, and this would be really annoying error report to resolve...

comment:2 Changed 3 years ago by aaugustin

  • Owner changed from nobody to aaugustin
  • Status changed from new to assigned

comment:3 Changed 3 years ago by aaugustin

  • Resolution set to invalid
  • Status changed from assigned to closed

This a well-known behavior of HTTP.

If your application requires caching with sub-second precision, then you should use ETags (USE_ETAGS = True) and disable ConditionalGetMiddleware. ETags were added to the HTTP protocol precisely to cater for the use case you're describing. In Django they are handled by CommonMiddleware.

The 'Date' header is usually set by the webserver, which is fine.

Last edited 3 years ago by aaugustin (previous) (diff)
Note: See TracTickets for help on using tickets.
Back to Top