Opened 11 years ago

Closed 11 years ago

Last modified 11 years ago

#19604 closed Bug (invalid)

Bug in conditional decorator for sub-second time intervals

Reported by: anonymous Owned by: Aymeric Augustin
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

Description

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 by Anssi Kääriäinen, 11 years ago

Triage Stage: UnreviewedAccepted

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

comment:2 by Aymeric Augustin, 11 years ago

Owner: changed from nobody to Aymeric Augustin
Status: newassigned

comment:3 by Aymeric Augustin, 11 years ago

Resolution: invalid
Status: assignedclosed

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 11 years ago by Aymeric Augustin (previous) (diff)
Note: See TracTickets for help on using tickets.
Back to Top