Opened 18 months ago

Closed 18 months ago

Last modified 18 months 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.

Attachments (0)

Change History (3)

comment:1 Changed 18 months 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 18 months ago by aaugustin

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

comment:3 Changed 18 months 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 18 months ago by aaugustin (previous) (diff)

Add Comment

Modify Ticket

Change Properties
<Author field>
as closed
as The resolution will be set. Next status will be 'closed'
The resolution will be deleted. Next status will be 'new'

E-mail address and user name can be saved in the Preferences.

Note: See TracTickets for help on using tickets.