diff options
Diffstat (limited to 'django/utils/http.py')
| -rw-r--r-- | django/utils/http.py | 55 |
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): |
