7 "expires", "lastmodified",
8 "prefixurl", "modified",
13 import sys, os, threading, urllib, urlparse
15 except ImportError: pass
16 import net, utils, webapi as web
18 def prefixurl(base=''):
20 Sorry, this function is really difficult to explain.
21 Maybe some other time.
23 url = web.ctx.path.lstrip('/')
24 for i in xrange(url.count('/')):
32 Outputs an `Expires` header for `delta` from now.
33 `delta` is a `timedelta` object or a number of seconds.
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))
40 def lastmodified(date_obj):
41 """Outputs a `Last-Modified` header for `datetime`."""
42 web.header('Last-Modified', net.httpdate(date_obj))
44 def modified(date=None, etag=None):
46 Checks to see if the page has been modified since the version in the
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.
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.
63 from __builtin__ import set
66 from sets import Set as set
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])
72 if '*' in n or etag in n:
75 # we subtract a second because
76 # HTTP dates don't have sub-second precision
77 if date-datetime.timedelta(seconds=1) <= m:
80 if date: lastmodified(date)
81 if etag: web.header('ETag', '"' + etag + '"')
83 raise web.notmodified()
87 def urlencode(query, doseq=0):
89 Same as urllib.urlencode, but supports unicode strings.
91 >>> urlencode({'text':'foo bar'})
93 >>> urlencode({'x': [1, 2]}, doseq=True)
96 def convert(value, doseq=False):
97 if doseq and isinstance(value, list):
98 return [convert(v) for v in value]
100 return utils.safestr(value)
102 query = dict([(k, convert(v, doseq)) for k, v in query.items()])
103 return urllib.urlencode(query, doseq=doseq)
105 def changequery(query=None, **kw):
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
112 query = web.rawinput(method='get')
113 for k, v in kw.iteritems():
120 out += '?' + urlencode(query, doseq=True)
123 def url(path=None, doseq=False, **kw):
125 Makes url by concatenating web.ctx.homepath and path and the
126 query string created using the arguments.
130 if path.startswith("/"):
131 out = web.ctx.homepath + path
136 out += '?' + urlencode(kw, doseq=doseq)
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
148 if __name__ == "__main__":