Skip to content
This repository
Newer
Older
100644 157 lines (137 sloc) 4.6 kb
089a01ab » aaronsw
2006-05-20 web.py 0.2
1 """
2 HTTP Utilities
3 (from web.py)
4 """
5
6 __all__ = [
7 "expires", "lastmodified",
8 "prefixurl", "modified",
9 "write",
874feb35 » anand
2007-02-17 bug fixes and web.url
10 "changequery", "url",
bb3ab9e7 » anandology
2008-11-10 removed reloader from http.py. It has been moved to application.py
11 "profiler",
089a01ab » aaronsw
2006-05-20 web.py 0.2
12 ]
13
14 import sys, os, threading, urllib, urlparse
15 try: import datetime
16 except ImportError: pass
17 import net, utils, webapi as web
18
19 def prefixurl(base=''):
20 """
21 Sorry, this function is really difficult to explain.
22 Maybe some other time.
23 """
24 url = web.ctx.path.lstrip('/')
25 for i in xrange(url.count('/')):
26 base += '../'
27 if not base:
28 base = './'
29 return base
30
31 def expires(delta):
32 """
33 Outputs an `Expires` header for `delta` from now.
34 `delta` is a `timedelta` object or a number of seconds.
35 """
36 if isinstance(delta, (int, long)):
37 delta = datetime.timedelta(seconds=delta)
38 date_obj = datetime.datetime.utcnow() + delta
39 web.header('Expires', net.httpdate(date_obj))
40
41 def lastmodified(date_obj):
42 """Outputs a `Last-Modified` header for `datetime`."""
43 web.header('Last-Modified', net.httpdate(date_obj))
44
45 def modified(date=None, etag=None):
d12fbe85 » aaronsw
2008-11-19 add docstring for web.modified; enhance function slightly
46 """
47 Checks to see if the page has been modified since the version in the
48 requester's cache.
49
50 When you publish pages, you can include `Last-Modified` and `ETag`
51 with the date the page was last modified and an opaque token for
52 the particular version, respectively. When readers reload the page,
53 the browser sends along the modification date and etag value for
54 the version it has in its cache. If the page hasn't changed,
55 the server can just return `304 Not Modified` and not have to
56 send the whole page again.
57
58 This function takes the last-modified date `date` and the ETag `etag`
59 and checks the headers to see if they match. If they do, it returns
60 `True` and sets the response status to `304 Not Modified`. It also
61 sets `Last-Modified and `ETag` output headers.
62 """
d8da2ccf » aaronsw
2008-10-23 bug fix (tx Justin Davis)
63 n = set(x.strip('" ') for x in web.ctx.env.get('HTTP_IF_NONE_MATCH', '').split(','))
089a01ab » aaronsw
2006-05-20 web.py 0.2
64 m = net.parsehttpdate(web.ctx.env.get('HTTP_IF_MODIFIED_SINCE', '').split(';')[0])
65 validate = False
66 if etag:
3ccd412a » aaronsw
2008-10-22 add etag support
67 if '*' in n or etag in n:
68 validate = True
089a01ab » aaronsw
2006-05-20 web.py 0.2
69 if date and m:
70 # we subtract a second because
71 # HTTP dates don't have sub-second precision
72 if date-datetime.timedelta(seconds=1) <= m:
73 validate = True
d12fbe85 » aaronsw
2008-11-19 add docstring for web.modified; enhance function slightly
74
089a01ab » aaronsw
2006-05-20 web.py 0.2
75 if validate: web.ctx.status = '304 Not Modified'
4f32f8bd » aaronsw
2008-12-11 fix in web.modified
76 if date: lastmodified(date)
77 if etag: web.header('ETag', '"' + etag + '"')
089a01ab » aaronsw
2006-05-20 web.py 0.2
78 return not validate
79
80 def write(cgi_response):
81 """
82 Converts a standard CGI-style string response into `header` and
83 `output` calls.
84 """
85 cgi_response = str(cgi_response)
86 cgi_response.replace('\r\n', '\n')
87 head, body = cgi_response.split('\n\n', 1)
88 lines = head.split('\n')
89
90 for line in lines:
91 if line.isspace():
92 continue
93 hdr, value = line.split(":", 1)
94 value = value.strip()
95 if hdr.lower() == "status":
96 web.ctx.status = value
97 else:
98 web.header(hdr, value)
99
100 web.output(body)
101
db64ef3f » aaronsw
2007-07-16 fix unicode bugs with urlencode
102 def urlencode(query):
103 """
104 Same as urllib.urlencode, but supports unicode strings.
105
106 >>> urlencode({'text':'foo bar'})
107 'text=foo+bar'
108 """
9d2a3e98 » anand
2007-08-07 fixed unicode bugs
109 query = dict([(k, utils.utf8(v)) for k, v in query.items()])
db64ef3f » aaronsw
2007-07-16 fix unicode bugs with urlencode
110 return urllib.urlencode(query)
111
3962c188 » anand
2007-08-15 changequery takes optional query argument.
112 def changequery(query=None, **kw):
089a01ab » aaronsw
2006-05-20 web.py 0.2
113 """
114 Imagine you're at `/foo?a=1&b=2`. Then `changequery(a=3)` will return
115 `/foo?a=3&b=2` -- the same URL but with the arguments you requested
116 changed.
117 """
3962c188 » anand
2007-08-15 changequery takes optional query argument.
118 if query is None:
119 query = web.input(_method='get')
089a01ab » aaronsw
2006-05-20 web.py 0.2
120 for k, v in kw.iteritems():
121 if v is None:
122 query.pop(k, None)
123 else:
124 query[k] = v
53fb28d4 » anand
2007-06-25 fixed bugs in changequery and redirect
125 out = web.ctx.path
089a01ab » aaronsw
2006-05-20 web.py 0.2
126 if query:
db64ef3f » aaronsw
2007-07-16 fix unicode bugs with urlencode
127 out += '?' + urlencode(query)
089a01ab » aaronsw
2006-05-20 web.py 0.2
128 return out
129
3962c188 » anand
2007-08-15 changequery takes optional query argument.
130 def url(path=None, **kw):
874feb35 » anand
2007-02-17 bug fixes and web.url
131 """
132 Makes url by concatinating web.ctx.homepath and path and the
133 query string created using the arguments.
134 """
3962c188 » anand
2007-08-15 changequery takes optional query argument.
135 if path is None:
136 path = web.ctx.path
874feb35 » anand
2007-02-17 bug fixes and web.url
137 if path.startswith("/"):
138 out = web.ctx.homepath + path
139 else:
140 out = path
141
142 if kw:
db64ef3f » aaronsw
2007-07-16 fix unicode bugs with urlencode
143 out += '?' + urlencode(kw)
874feb35 » anand
2007-02-17 bug fixes and web.url
144
145 return out
146
089a01ab » aaronsw
2006-05-20 web.py 0.2
147 def profiler(app):
148 """Outputs basic profiling information at the bottom of each response."""
cb2115cd » aaronsw
2006-11-10 fix profiling bug (tx spez)
149 from utils import profile
089a01ab » aaronsw
2006-05-20 web.py 0.2
150 def profile_internal(e, o):
151 out, result = profile(app)(e, o)
152 return out + ['<pre>' + net.websafe(result) + '</pre>']
153 return profile_internal
154
155 if __name__ == "__main__":
156 import doctest
157 doctest.testmod()
Something went wrong with that request. Please try again.