OpenSecurity/install/web.py-0.37/build/lib/web/http.py
author om
Mon, 02 Dec 2013 14:02:05 +0100
changeset 3 65432e6c6042
permissions -rwxr-xr-x
initial deployment and project layout commit
om@3
     1
"""
om@3
     2
HTTP Utilities
om@3
     3
(from web.py)
om@3
     4
"""
om@3
     5
om@3
     6
__all__ = [
om@3
     7
  "expires", "lastmodified", 
om@3
     8
  "prefixurl", "modified", 
om@3
     9
  "changequery", "url",
om@3
    10
  "profiler",
om@3
    11
]
om@3
    12
om@3
    13
import sys, os, threading, urllib, urlparse
om@3
    14
try: import datetime
om@3
    15
except ImportError: pass
om@3
    16
import net, utils, webapi as web
om@3
    17
om@3
    18
def prefixurl(base=''):
om@3
    19
    """
om@3
    20
    Sorry, this function is really difficult to explain.
om@3
    21
    Maybe some other time.
om@3
    22
    """
om@3
    23
    url = web.ctx.path.lstrip('/')
om@3
    24
    for i in xrange(url.count('/')): 
om@3
    25
        base += '../'
om@3
    26
    if not base: 
om@3
    27
        base = './'
om@3
    28
    return base
om@3
    29
om@3
    30
def expires(delta):
om@3
    31
    """
om@3
    32
    Outputs an `Expires` header for `delta` from now. 
om@3
    33
    `delta` is a `timedelta` object or a number of seconds.
om@3
    34
    """
om@3
    35
    if isinstance(delta, (int, long)):
om@3
    36
        delta = datetime.timedelta(seconds=delta)
om@3
    37
    date_obj = datetime.datetime.utcnow() + delta
om@3
    38
    web.header('Expires', net.httpdate(date_obj))
om@3
    39
om@3
    40
def lastmodified(date_obj):
om@3
    41
    """Outputs a `Last-Modified` header for `datetime`."""
om@3
    42
    web.header('Last-Modified', net.httpdate(date_obj))
om@3
    43
om@3
    44
def modified(date=None, etag=None):
om@3
    45
    """
om@3
    46
    Checks to see if the page has been modified since the version in the
om@3
    47
    requester's cache.
om@3
    48
    
om@3
    49
    When you publish pages, you can include `Last-Modified` and `ETag`
om@3
    50
    with the date the page was last modified and an opaque token for
om@3
    51
    the particular version, respectively. When readers reload the page, 
om@3
    52
    the browser sends along the modification date and etag value for
om@3
    53
    the version it has in its cache. If the page hasn't changed, 
om@3
    54
    the server can just return `304 Not Modified` and not have to 
om@3
    55
    send the whole page again.
om@3
    56
    
om@3
    57
    This function takes the last-modified date `date` and the ETag `etag`
om@3
    58
    and checks the headers to see if they match. If they do, it returns 
om@3
    59
    `True`, or otherwise it raises NotModified error. It also sets 
om@3
    60
    `Last-Modified` and `ETag` output headers.
om@3
    61
    """
om@3
    62
    try:
om@3
    63
        from __builtin__ import set
om@3
    64
    except ImportError:
om@3
    65
        # for python 2.3
om@3
    66
        from sets import Set as set
om@3
    67
om@3
    68
    n = set([x.strip('" ') for x in web.ctx.env.get('HTTP_IF_NONE_MATCH', '').split(',')])
om@3
    69
    m = net.parsehttpdate(web.ctx.env.get('HTTP_IF_MODIFIED_SINCE', '').split(';')[0])
om@3
    70
    validate = False
om@3
    71
    if etag:
om@3
    72
        if '*' in n or etag in n:
om@3
    73
            validate = True
om@3
    74
    if date and m:
om@3
    75
        # we subtract a second because 
om@3
    76
        # HTTP dates don't have sub-second precision
om@3
    77
        if date-datetime.timedelta(seconds=1) <= m:
om@3
    78
            validate = True
om@3
    79
    
om@3
    80
    if date: lastmodified(date)
om@3
    81
    if etag: web.header('ETag', '"' + etag + '"')
om@3
    82
    if validate:
om@3
    83
        raise web.notmodified()
om@3
    84
    else:
om@3
    85
        return True
om@3
    86
om@3
    87
def urlencode(query, doseq=0):
om@3
    88
    """
om@3
    89
    Same as urllib.urlencode, but supports unicode strings.
om@3
    90
    
om@3
    91
        >>> urlencode({'text':'foo bar'})
om@3
    92
        'text=foo+bar'
om@3
    93
        >>> urlencode({'x': [1, 2]}, doseq=True)
om@3
    94
        'x=1&x=2'
om@3
    95
    """
om@3
    96
    def convert(value, doseq=False):
om@3
    97
        if doseq and isinstance(value, list):
om@3
    98
            return [convert(v) for v in value]
om@3
    99
        else:
om@3
   100
            return utils.safestr(value)
om@3
   101
        
om@3
   102
    query = dict([(k, convert(v, doseq)) for k, v in query.items()])
om@3
   103
    return urllib.urlencode(query, doseq=doseq)
om@3
   104
om@3
   105
def changequery(query=None, **kw):
om@3
   106
    """
om@3
   107
    Imagine you're at `/foo?a=1&b=2`. Then `changequery(a=3)` will return
om@3
   108
    `/foo?a=3&b=2` -- the same URL but with the arguments you requested
om@3
   109
    changed.
om@3
   110
    """
om@3
   111
    if query is None:
om@3
   112
        query = web.rawinput(method='get')
om@3
   113
    for k, v in kw.iteritems():
om@3
   114
        if v is None:
om@3
   115
            query.pop(k, None)
om@3
   116
        else:
om@3
   117
            query[k] = v
om@3
   118
    out = web.ctx.path
om@3
   119
    if query:
om@3
   120
        out += '?' + urlencode(query, doseq=True)
om@3
   121
    return out
om@3
   122
om@3
   123
def url(path=None, doseq=False, **kw):
om@3
   124
    """
om@3
   125
    Makes url by concatenating web.ctx.homepath and path and the 
om@3
   126
    query string created using the arguments.
om@3
   127
    """
om@3
   128
    if path is None:
om@3
   129
        path = web.ctx.path
om@3
   130
    if path.startswith("/"):
om@3
   131
        out = web.ctx.homepath + path
om@3
   132
    else:
om@3
   133
        out = path
om@3
   134
om@3
   135
    if kw:
om@3
   136
        out += '?' + urlencode(kw, doseq=doseq)
om@3
   137
    
om@3
   138
    return out
om@3
   139
om@3
   140
def profiler(app):
om@3
   141
    """Outputs basic profiling information at the bottom of each response."""
om@3
   142
    from utils import profile
om@3
   143
    def profile_internal(e, o):
om@3
   144
        out, result = profile(app)(e, o)
om@3
   145
        return list(out) + ['<pre>' + net.websafe(result) + '</pre>']
om@3
   146
    return profile_internal
om@3
   147
om@3
   148
if __name__ == "__main__":
om@3
   149
    import doctest
om@3
   150
    doctest.testmod()