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
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
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
41 """Outputs a `Last-Modified` header for `datetime`."""
42 web.header('Last-Modified', net.httpdate(date_obj))
43
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
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
76
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
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
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
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