summaryrefslogtreecommitdiff
path: root/django/utils/http.py
diff options
context:
space:
mode:
Diffstat (limited to 'django/utils/http.py')
-rw-r--r--django/utils/http.py55
1 files changed, 55 insertions, 0 deletions
diff --git a/django/utils/http.py b/django/utils/http.py
index 49d067e57c..61623fc696 100644
--- a/django/utils/http.py
+++ b/django/utils/http.py
@@ -1,3 +1,5 @@
+import calendar
+import datetime
import re
import sys
import urllib
@@ -8,6 +10,17 @@ from django.utils.functional import allow_lazy
ETAG_MATCH = re.compile(r'(?:W/)?"((?:\\.|[^"])*)"')
+MONTHS = 'jan feb mar apr may jun jul aug sep oct nov dec'.split()
+__D = r'(?P<day>\d{2})'
+__D2 = r'(?P<day>[ \d]\d)'
+__M = r'(?P<mon>\w{3})'
+__Y = r'(?P<year>\d{4})'
+__Y2 = r'(?P<year>\d{2})'
+__T = r'(?P<hour>\d{2}):(?P<min>\d{2}):(?P<sec>\d{2})'
+RFC1123_DATE = re.compile(r'^\w{3}, %s %s %s %s GMT$' % (__D, __M, __Y, __T))
+RFC850_DATE = re.compile(r'^\w{6,9}, %s-%s-%s %s GMT$' % (__D, __M, __Y2, __T))
+ASCTIME_DATE = re.compile(r'^\w{3} %s %s %s %s$' % (__M, __D2, __T, __Y))
+
def urlquote(url, safe='/'):
"""
A version of Python's urllib.quote() function that can operate on unicode
@@ -70,6 +83,48 @@ def http_date(epoch_seconds=None):
rfcdate = formatdate(epoch_seconds)
return '%s GMT' % rfcdate[:25]
+def parse_http_date(date):
+ """
+ Parses a date format as specified by HTTP RFC2616 section 3.3.1.
+
+ The three formats allowed by the RFC are accepted, even if only the first
+ one is still in widespread use.
+
+ Returns an floating point number expressed in seconds since the epoch, in
+ UTC.
+ """
+ # emails.Util.parsedate does the job for RFC1123 dates; unfortunately
+ # RFC2616 makes it mandatory to support RFC850 dates too. So we roll
+ # our own RFC-compliant parsing.
+ for regex in RFC1123_DATE, RFC850_DATE, ASCTIME_DATE:
+ m = regex.match(date)
+ if m is not None:
+ break
+ else:
+ raise ValueError("%r is not in a valid HTTP date format" % date)
+ try:
+ year = int(m.group('year'))
+ if year < 100:
+ year += 2000 if year < 70 else 1900
+ month = MONTHS.index(m.group('mon').lower()) + 1
+ day = int(m.group('day'))
+ hour = int(m.group('hour'))
+ min = int(m.group('min'))
+ sec = int(m.group('sec'))
+ result = datetime.datetime(year, month, day, hour, min, sec)
+ return calendar.timegm(result.utctimetuple())
+ except Exception:
+ raise ValueError("%r is not a valid date" % date)
+
+def parse_http_date_safe(date):
+ """
+ Same as parse_http_date, but returns None if the input is invalid.
+ """
+ try:
+ return parse_http_date(date)
+ except Exception:
+ pass
+
# Base 36 functions: useful for generating compact URLs
def base36_to_int(s):