Opened 18 years ago

Closed 17 years ago

#4119 closed (fixed)

Incorrect HTTP-Date format in expire field of HTTP Header

Reported by: Jari Pennanen Owned by: Malcolm Tredinnick
Component: Contrib apps Version: dev
Severity: Keywords: http-date header
Cc: Triage Stage: Accepted
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

Currently the Django uses datetime.strftime to format it's HTTP-Date, because strftime is localized function it should not be used for it.

Changing locales to something else than English will break Django's session system on some browsers at the current state.

Using datetime.ctime instead makes Django's HTTP-Date format automatically correct and it is not anymore locale dependent. ctime function also automatically handles the GMT conversion if needed, that is why the patch also changes the utcnow to now. It conforms the HTTP Specification clearly as in here HTTP Specs is stated (the third choice).

This fixes only expire field in django.contrib.session.middleware but the problem might be elsewhere too (mostly where HTTP-Date is used). Common rule is that strftime is not meant for fixed date formats.

Attachments (4)

middleware.py.diff (1.0 KB ) - added by Jari Pennanen 18 years ago.
Fix for django.contrib.sessions.middleware locale dependency
middleware.py.2.diff (935 bytes ) - added by Jari Pennanen 18 years ago.
Fix for django.contrib.sessions.middleware locale dependency (first one had incorrect paths)
middleware.py.3.diff (938 bytes ) - added by Jari Pennanen 18 years ago.
Same fix, but apparenlty assumption of GMT convert was wrong. This uses utcnow again.
ticket4119.diff (4.8 KB ) - added by Chris Bennett <chrisrbennett@…> 17 years ago.
fixes for this ticket

Download all attachments as: .zip

Change History (17)

by Jari Pennanen, 18 years ago

Attachment: middleware.py.diff added

Fix for django.contrib.sessions.middleware locale dependency

by Jari Pennanen, 18 years ago

Attachment: middleware.py.2.diff added

Fix for django.contrib.sessions.middleware locale dependency (first one had incorrect paths)

comment:1 by Jari Pennanen, 18 years ago

Sorry about the duplicate patch, but apparently the first patch had wrong path.

by Jari Pennanen, 18 years ago

Attachment: middleware.py.3.diff added

Same fix, but apparenlty assumption of GMT convert was wrong. This uses utcnow again.

comment:2 by Jari Pennanen, 18 years ago

One addition, the orginal "%a, %d-%b-%Y %H:%M:%S GMT" even in plain English is incorrect. It does not conform any of those three in HTTP Specs. So if this patch is not added then patch with strftime fixed is needed.

comment:3 by Simon G. <dev@…>, 18 years ago

Triage Stage: UnreviewedReady for checkin

comment:4 by Malcolm Tredinnick, 18 years ago

Triage Stage: Ready for checkinAccepted

Patch needs improving on two fronts:

  1. It looks like utils/cache.py at least has the same problem (just grepping for "expires"). Other places needs searching, too.
  2. Because we send out HTTP/1.1 responses (at least sometimes), we MUST use the first format ine section 3.3.1 of the HTTP 1.1 RFC. The attached patch implements the third format. So the date format needs improvement.

comment:5 by Malcolm Tredinnick, 18 years ago

Patch needs improvement: set

in reply to:  5 ; comment:6 by anonymous, 18 years ago

Replying to mtredinnick:
What better patch do I need? Change it to strftime perhaps?

in reply to:  6 comment:7 by Malcolm Tredinnick, 18 years ago

Replying to anonymous:

What better patch do I need? Change it to strftime perhaps?

Whichever way you do it, the produced header string should exactly match the first format shown in section 3.3.1 of the HTTP/1.1 spec. Read the paragraph just under the examples in that section and you'll see that is marked as a "MUST" requirement. So whether there is time or datetime method that does it directly (in a locale-independent fashion) or whether we have to construct it by hand, that's the format we need to generate.

The important point about that format is that it is always the same number of characters long. It uses two-digit, zero-padded dates and hour values and four-digit years, for example.

by Chris Bennett <chrisrbennett@…>, 17 years ago

Attachment: ticket4119.diff added

fixes for this ticket

comment:8 by Chris Bennett <chrisrbennett@…>, 17 years ago

Patch needs improvement: unset

Attaching a patch that addresses the locale-dependency of strftime to address the requirement of HTTP/1.1 RFC2616 3.3.1:

email.utils.formatdate() returns a correctly formatted fixed length date without consideration of current locale (which is the correct behavior) for consideration of the HTTP RFC standards. (I don't like the name of the module this method is coming from either.)

Important notes about this patch:

  • I fixed a bug relating to the interpretation of the boolean True value in django/utils/cache.py (line 46) - it now reflects the behavior as described in the docstring above it. (So passing in max_age=1 does not result in the "Cache-Control" header being populated with simply "max-age")
  • The discussion in this ticket is confusing. The summary refers to "expire field of HTTP header" where the previously submitted patches attempt to fix _cookies_. This patch resolves that issue, in addition to fixing incorrect _HTTP response headers_ that should contain an HTTP 3.3.1 formatted date.
  • The '+ "GMT"' tackyness is to insure support with Python 2.3, whose formatdate() method does not yet have the usegmt enhancement.

Hope this helps, Chris

comment:9 by Malcolm Tredinnick, 17 years ago

Owner: changed from Adrian Holovaty to Malcolm Tredinnick

You can always spot the python 2.5 users: email.utils is new in Python 2.5. It's called email.Utils in 2.3 and 2.4 and 2.5 also understands that name (there's an alias in email/init.py). So you should import email.Utils everywhere.

Other than that, the patch looks great. Agree with all your comments (including the discussion being confusing). I'll give it another review and check it in when I get a chance.

comment:10 by Malcolm Tredinnick, 17 years ago

Resolution: fixed
Status: newclosed

Fixed in [5712] (although I typed the wrong ticket number into the commit message).

comment:11 by Gary Wilson, 17 years ago

Resolution: fixed
Status: closedreopened

It appears that [6333] reverted this fix.

in reply to:  11 comment:12 by Gary Wilson, 17 years ago

Replying to gwilson:

It appears that [6333] reverted this fix.

In django/trunk/django/contrib/sessions/middleware.py.

comment:13 by Malcolm Tredinnick, 17 years ago

Resolution: fixed
Status: reopenedclosed

#5816 is an attempt to fix the revert, so let's leave that as the active ticket.

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