1 """Functions for builtin CherryPy tools."""
2
3 import md5
4 import re
5
6 import cherrypy
7 from cherrypy.lib import http as _http
8
9
10
11
67
93
94
95
96
97 -def proxy(base=None, local='X-Forwarded-Host', remote='X-Forwarded-For',
98 scheme='X-Forwarded-Proto'):
99 """Change the base URL (scheme://host[:port][/path]).
100
101 For running a CP server behind Apache, lighttpd, or other HTTP server.
102
103 If you want the new request.base to include path info (not just the host),
104 you must explicitly set base to the full base path, and ALSO set 'local'
105 to '', so that the X-Forwarded-Host request header (which never includes
106 path info) does not override it.
107
108 cherrypy.request.remote.ip (the IP address of the client) will be
109 rewritten if the header specified by the 'remote' arg is valid.
110 By default, 'remote' is set to 'X-Forwarded-For'. If you do not
111 want to rewrite remote.ip, set the 'remote' arg to an empty string.
112 """
113
114 request = cherrypy.request
115
116 if scheme:
117 scheme = request.headers.get(scheme, None)
118 if not scheme:
119 scheme = request.base[:request.base.find("://")]
120
121 if local:
122 base = request.headers.get(local, base)
123 if not base:
124 port = cherrypy.request.local.port
125 if port == 80:
126 base = 'localhost'
127 else:
128 base = 'localhost:%s' % port
129
130 if base.find("://") == -1:
131
132 base = scheme + "://" + base
133
134 request.base = base
135
136 if remote:
137 xff = request.headers.get(remote)
138 if xff:
139 if remote == 'X-Forwarded-For':
140
141 xff = xff.split(',')[-1].strip()
142 request.remote.ip = xff
143
144
146 """Delete request headers whose field names are included in 'headers'.
147
148 This is a useful tool for working behind certain HTTP servers;
149 for example, Apache duplicates the work that CP does for 'Range'
150 headers, and will doubly-truncate the response.
151 """
152 request = cherrypy.request
153 for name in headers:
154 if name in request.headers:
155 del request.headers[name]
156
157
162 response_headers.failsafe = True
163
164
165 -def referer(pattern, accept=True, accept_missing=False, error=403,
166 message='Forbidden Referer header.'):
167 """Raise HTTPError if Referer header does not pass our test.
168
169 pattern: a regular expression pattern to test against the Referer.
170 accept: if True, the Referer must match the pattern; if False,
171 the Referer must NOT match the pattern.
172 accept_missing: if True, permit requests with no Referer header.
173 error: the HTTP error code to return to the client on failure.
174 message: a string to include in the response body on failure.
175 """
176 try:
177 match = bool(re.match(pattern, cherrypy.request.headers['Referer']))
178 if accept == match:
179 return
180 except KeyError:
181 if accept_missing:
182 return
183
184 raise cherrypy.HTTPError(error, message)
185
186
188 """Assert that the user is logged in."""
189
190 session_key = "username"
191
194
196 """Provide a temporary user name for anonymous users."""
197 pass
198
201
204
207
208 - def login_screen(self, from_page='..', username='', error_msg=''):
209 return """<html><body>
210 Message: %(error_msg)s
211 <form method="post" action="do_login">
212 Login: <input type="text" name="username" value="%(username)s" size="10" /><br />
213 Password: <input type="password" name="password" size="10" /><br />
214 <input type="hidden" name="from_page" value="%(from_page)s" /><br />
215 <input type="submit" />
216 </form>
217 </body></html>""" % {'from_page': from_page, 'username': username,
218 'error_msg': error_msg}
219
220 - def do_login(self, username, password, from_page='..'):
234
244
261
273
274
280 session_auth.__doc__ = """Session authentication hook.
281
282 Any attribute of the SessionAuth class may be overridden via a keyword arg
283 to this function:
284
285 """ + "\n".join(["%s: %s" % (k, type(getattr(SessionAuth, k)).__name__)
286 for k in dir(SessionAuth) if not k.startswith("__")])
287
288
293