web/lib/django/utils/http.py
changeset 38 77b6da96e6f1
parent 0 0d40e90630ef
equal deleted inserted replaced
37:8d941af65caf 38:77b6da96e6f1
       
     1 import re
       
     2 import urllib
       
     3 from email.Utils import formatdate
       
     4 
       
     5 from django.utils.encoding import smart_str, force_unicode
       
     6 from django.utils.functional import allow_lazy
       
     7 
       
     8 ETAG_MATCH = re.compile(r'(?:W/)?"((?:\\.|[^"])*)"')
       
     9 
       
    10 def urlquote(url, safe='/'):
       
    11     """
       
    12     A version of Python's urllib.quote() function that can operate on unicode
       
    13     strings. The url is first UTF-8 encoded before quoting. The returned string
       
    14     can safely be used as part of an argument to a subsequent iri_to_uri() call
       
    15     without double-quoting occurring.
       
    16     """
       
    17     return force_unicode(urllib.quote(smart_str(url), safe))
       
    18 
       
    19 urlquote = allow_lazy(urlquote, unicode)
       
    20 
       
    21 def urlquote_plus(url, safe=''):
       
    22     """
       
    23     A version of Python's urllib.quote_plus() function that can operate on
       
    24     unicode strings. The url is first UTF-8 encoded before quoting. The
       
    25     returned string can safely be used as part of an argument to a subsequent
       
    26     iri_to_uri() call without double-quoting occurring.
       
    27     """
       
    28     return force_unicode(urllib.quote_plus(smart_str(url), safe))
       
    29 urlquote_plus = allow_lazy(urlquote_plus, unicode)
       
    30 
       
    31 def urlencode(query, doseq=0):
       
    32     """
       
    33     A version of Python's urllib.urlencode() function that can operate on
       
    34     unicode strings. The parameters are first case to UTF-8 encoded strings and
       
    35     then encoded as per normal.
       
    36     """
       
    37     if hasattr(query, 'items'):
       
    38         query = query.items()
       
    39     return urllib.urlencode(
       
    40         [(smart_str(k),
       
    41          isinstance(v, (list,tuple)) and [smart_str(i) for i in v] or smart_str(v))
       
    42             for k, v in query],
       
    43         doseq)
       
    44 
       
    45 def cookie_date(epoch_seconds=None):
       
    46     """
       
    47     Formats the time to ensure compatibility with Netscape's cookie standard.
       
    48 
       
    49     Accepts a floating point number expressed in seconds since the epoch, in
       
    50     UTC - such as that outputted by time.time(). If set to None, defaults to
       
    51     the current time.
       
    52 
       
    53     Outputs a string in the format 'Wdy, DD-Mon-YYYY HH:MM:SS GMT'.
       
    54     """
       
    55     rfcdate = formatdate(epoch_seconds)
       
    56     return '%s-%s-%s GMT' % (rfcdate[:7], rfcdate[8:11], rfcdate[12:25])
       
    57 
       
    58 def http_date(epoch_seconds=None):
       
    59     """
       
    60     Formats the time to match the RFC1123 date format as specified by HTTP
       
    61     RFC2616 section 3.3.1.
       
    62 
       
    63     Accepts a floating point number expressed in seconds since the epoch, in
       
    64     UTC - such as that outputted by time.time(). If set to None, defaults to
       
    65     the current time.
       
    66 
       
    67     Outputs a string in the format 'Wdy, DD Mon YYYY HH:MM:SS GMT'.
       
    68     """
       
    69     rfcdate = formatdate(epoch_seconds)
       
    70     return '%s GMT' % rfcdate[:25]
       
    71 
       
    72 # Base 36 functions: useful for generating compact URLs
       
    73 
       
    74 def base36_to_int(s):
       
    75     """
       
    76     Convertd a base 36 string to an integer
       
    77     """
       
    78     return int(s, 36)
       
    79 
       
    80 def int_to_base36(i):
       
    81     """
       
    82     Converts an integer to a base36 string
       
    83     """
       
    84     digits = "0123456789abcdefghijklmnopqrstuvwxyz"
       
    85     factor = 0
       
    86     # Find starting factor
       
    87     while True:
       
    88         factor += 1
       
    89         if i < 36 ** factor:
       
    90             factor -= 1
       
    91             break
       
    92     base36 = []
       
    93     # Construct base36 representation
       
    94     while factor >= 0:
       
    95         j = 36 ** factor
       
    96         base36.append(digits[i / j])
       
    97         i = i % j
       
    98         factor -= 1
       
    99     return ''.join(base36)
       
   100 
       
   101 def parse_etags(etag_str):
       
   102     """
       
   103     Parses a string with one or several etags passed in If-None-Match and
       
   104     If-Match headers by the rules in RFC 2616. Returns a list of etags
       
   105     without surrounding double quotes (") and unescaped from \<CHAR>.
       
   106     """
       
   107     etags = ETAG_MATCH.findall(etag_str)
       
   108     if not etags:
       
   109         # etag_str has wrong format, treat it as an opaque string then
       
   110         return [etag_str]
       
   111     etags = [e.decode('string_escape') for e in etags]
       
   112     return etags
       
   113 
       
   114 def quote_etag(etag):
       
   115     """
       
   116     Wraps a string in double quotes escaping contents as necesary.
       
   117     """
       
   118     return '"%s"' % etag.replace('\\', '\\\\').replace('"', '\\"')
       
   119