web.web.http

Package web :: Package web :: Module http |
[hide private]
[frames] | no frames]

# Source Code for Module web.web.http

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