Mercurial > public > mercurial-scm > hg-stable
comparison mercurial/hgweb/hgwebdir_mod.py @ 36812:b9b968e21f78
hgweb: rename req to wsgireq
We will soon introduce a parsed WSGI request object so we don't
have to concern ourselves with low-level WSGI matters. Prepare
for multiple request objects by renaming the existing one so it
is clear it deals with WSGI.
We also remove a symbol import to avoid even more naming confusion.
# no-check-commit because of some new foo_bar naming that's required
Differential Revision: https://phab.mercurial-scm.org/D2732
author | Gregory Szorc <gregory.szorc@gmail.com> |
---|---|
date | Thu, 08 Mar 2018 15:15:59 -0800 |
parents | c6061cadb400 |
children | ec46415ed826 |
comparison
equal
deleted
inserted
replaced
36811:8e1556ac01bb | 36812:b9b968e21f78 |
---|---|
24 get_mtime, | 24 get_mtime, |
25 ismember, | 25 ismember, |
26 paritygen, | 26 paritygen, |
27 staticfile, | 27 staticfile, |
28 ) | 28 ) |
29 from .request import wsgirequest | |
30 | 29 |
31 from .. import ( | 30 from .. import ( |
32 configitems, | 31 configitems, |
33 encoding, | 32 encoding, |
34 error, | 33 error, |
41 util, | 40 util, |
42 ) | 41 ) |
43 | 42 |
44 from . import ( | 43 from . import ( |
45 hgweb_mod, | 44 hgweb_mod, |
45 request as requestmod, | |
46 webutil, | 46 webutil, |
47 wsgicgi, | 47 wsgicgi, |
48 ) | 48 ) |
49 from ..utils import dateutil | 49 from ..utils import dateutil |
50 | 50 |
195 raise RuntimeError("This function is only intended to be " | 195 raise RuntimeError("This function is only intended to be " |
196 "called while running as a CGI script.") | 196 "called while running as a CGI script.") |
197 wsgicgi.launch(self) | 197 wsgicgi.launch(self) |
198 | 198 |
199 def __call__(self, env, respond): | 199 def __call__(self, env, respond): |
200 req = wsgirequest(env, respond) | 200 wsgireq = requestmod.wsgirequest(env, respond) |
201 return self.run_wsgi(req) | 201 return self.run_wsgi(wsgireq) |
202 | 202 |
203 def read_allowed(self, ui, req): | 203 def read_allowed(self, ui, wsgireq): |
204 """Check allow_read and deny_read config options of a repo's ui object | 204 """Check allow_read and deny_read config options of a repo's ui object |
205 to determine user permissions. By default, with neither option set (or | 205 to determine user permissions. By default, with neither option set (or |
206 both empty), allow all users to read the repo. There are two ways a | 206 both empty), allow all users to read the repo. There are two ways a |
207 user can be denied read access: (1) deny_read is not empty, and the | 207 user can be denied read access: (1) deny_read is not empty, and the |
208 user is unauthenticated or deny_read contains user (or *), and (2) | 208 user is unauthenticated or deny_read contains user (or *), and (2) |
209 allow_read is not empty and the user is not in allow_read. Return True | 209 allow_read is not empty and the user is not in allow_read. Return True |
210 if user is allowed to read the repo, else return False.""" | 210 if user is allowed to read the repo, else return False.""" |
211 | 211 |
212 user = req.env.get('REMOTE_USER') | 212 user = wsgireq.env.get('REMOTE_USER') |
213 | 213 |
214 deny_read = ui.configlist('web', 'deny_read', untrusted=True) | 214 deny_read = ui.configlist('web', 'deny_read', untrusted=True) |
215 if deny_read and (not user or ismember(ui, user, deny_read)): | 215 if deny_read and (not user or ismember(ui, user, deny_read)): |
216 return False | 216 return False |
217 | 217 |
220 if (not allow_read) or ismember(ui, user, allow_read): | 220 if (not allow_read) or ismember(ui, user, allow_read): |
221 return True | 221 return True |
222 | 222 |
223 return False | 223 return False |
224 | 224 |
225 def run_wsgi(self, req): | 225 def run_wsgi(self, wsgireq): |
226 profile = self.ui.configbool('profiling', 'enabled') | 226 profile = self.ui.configbool('profiling', 'enabled') |
227 with profiling.profile(self.ui, enabled=profile): | 227 with profiling.profile(self.ui, enabled=profile): |
228 for r in self._runwsgi(req): | 228 for r in self._runwsgi(wsgireq): |
229 yield r | 229 yield r |
230 | 230 |
231 def _runwsgi(self, req): | 231 def _runwsgi(self, wsgireq): |
232 try: | 232 try: |
233 self.refresh() | 233 self.refresh() |
234 | 234 |
235 csp, nonce = cspvalues(self.ui) | 235 csp, nonce = cspvalues(self.ui) |
236 if csp: | 236 if csp: |
237 req.headers.append(('Content-Security-Policy', csp)) | 237 wsgireq.headers.append(('Content-Security-Policy', csp)) |
238 | 238 |
239 virtual = req.env.get("PATH_INFO", "").strip('/') | 239 virtual = wsgireq.env.get("PATH_INFO", "").strip('/') |
240 tmpl = self.templater(req, nonce) | 240 tmpl = self.templater(wsgireq, nonce) |
241 ctype = tmpl('mimetype', encoding=encoding.encoding) | 241 ctype = tmpl('mimetype', encoding=encoding.encoding) |
242 ctype = templater.stringify(ctype) | 242 ctype = templater.stringify(ctype) |
243 | 243 |
244 # a static file | 244 # a static file |
245 if virtual.startswith('static/') or 'static' in req.form: | 245 if virtual.startswith('static/') or 'static' in wsgireq.form: |
246 if virtual.startswith('static/'): | 246 if virtual.startswith('static/'): |
247 fname = virtual[7:] | 247 fname = virtual[7:] |
248 else: | 248 else: |
249 fname = req.form['static'][0] | 249 fname = wsgireq.form['static'][0] |
250 static = self.ui.config("web", "static", None, | 250 static = self.ui.config("web", "static", None, |
251 untrusted=False) | 251 untrusted=False) |
252 if not static: | 252 if not static: |
253 tp = self.templatepath or templater.templatepaths() | 253 tp = self.templatepath or templater.templatepaths() |
254 if isinstance(tp, str): | 254 if isinstance(tp, str): |
255 tp = [tp] | 255 tp = [tp] |
256 static = [os.path.join(p, 'static') for p in tp] | 256 static = [os.path.join(p, 'static') for p in tp] |
257 staticfile(static, fname, req) | 257 staticfile(static, fname, wsgireq) |
258 return [] | 258 return [] |
259 | 259 |
260 # top-level index | 260 # top-level index |
261 | 261 |
262 repos = dict(self.repos) | 262 repos = dict(self.repos) |
263 | 263 |
264 if (not virtual or virtual == 'index') and virtual not in repos: | 264 if (not virtual or virtual == 'index') and virtual not in repos: |
265 req.respond(HTTP_OK, ctype) | 265 wsgireq.respond(HTTP_OK, ctype) |
266 return self.makeindex(req, tmpl) | 266 return self.makeindex(wsgireq, tmpl) |
267 | 267 |
268 # nested indexes and hgwebs | 268 # nested indexes and hgwebs |
269 | 269 |
270 if virtual.endswith('/index') and virtual not in repos: | 270 if virtual.endswith('/index') and virtual not in repos: |
271 subdir = virtual[:-len('index')] | 271 subdir = virtual[:-len('index')] |
272 if any(r.startswith(subdir) for r in repos): | 272 if any(r.startswith(subdir) for r in repos): |
273 req.respond(HTTP_OK, ctype) | 273 wsgireq.respond(HTTP_OK, ctype) |
274 return self.makeindex(req, tmpl, subdir) | 274 return self.makeindex(wsgireq, tmpl, subdir) |
275 | 275 |
276 def _virtualdirs(): | 276 def _virtualdirs(): |
277 # Check the full virtual path, each parent, and the root ('') | 277 # Check the full virtual path, each parent, and the root ('') |
278 if virtual != '': | 278 if virtual != '': |
279 yield virtual | 279 yield virtual |
284 yield '' | 284 yield '' |
285 | 285 |
286 for virtualrepo in _virtualdirs(): | 286 for virtualrepo in _virtualdirs(): |
287 real = repos.get(virtualrepo) | 287 real = repos.get(virtualrepo) |
288 if real: | 288 if real: |
289 req.env['REPO_NAME'] = virtualrepo | 289 wsgireq.env['REPO_NAME'] = virtualrepo |
290 try: | 290 try: |
291 # ensure caller gets private copy of ui | 291 # ensure caller gets private copy of ui |
292 repo = hg.repository(self.ui.copy(), real) | 292 repo = hg.repository(self.ui.copy(), real) |
293 return hgweb_mod.hgweb(repo).run_wsgi(req) | 293 return hgweb_mod.hgweb(repo).run_wsgi(wsgireq) |
294 except IOError as inst: | 294 except IOError as inst: |
295 msg = encoding.strtolocal(inst.strerror) | 295 msg = encoding.strtolocal(inst.strerror) |
296 raise ErrorResponse(HTTP_SERVER_ERROR, msg) | 296 raise ErrorResponse(HTTP_SERVER_ERROR, msg) |
297 except error.RepoError as inst: | 297 except error.RepoError as inst: |
298 raise ErrorResponse(HTTP_SERVER_ERROR, bytes(inst)) | 298 raise ErrorResponse(HTTP_SERVER_ERROR, bytes(inst)) |
299 | 299 |
300 # browse subdirectories | 300 # browse subdirectories |
301 subdir = virtual + '/' | 301 subdir = virtual + '/' |
302 if [r for r in repos if r.startswith(subdir)]: | 302 if [r for r in repos if r.startswith(subdir)]: |
303 req.respond(HTTP_OK, ctype) | 303 wsgireq.respond(HTTP_OK, ctype) |
304 return self.makeindex(req, tmpl, subdir) | 304 return self.makeindex(wsgireq, tmpl, subdir) |
305 | 305 |
306 # prefixes not found | 306 # prefixes not found |
307 req.respond(HTTP_NOT_FOUND, ctype) | 307 wsgireq.respond(HTTP_NOT_FOUND, ctype) |
308 return tmpl("notfound", repo=virtual) | 308 return tmpl("notfound", repo=virtual) |
309 | 309 |
310 except ErrorResponse as err: | 310 except ErrorResponse as err: |
311 req.respond(err, ctype) | 311 wsgireq.respond(err, ctype) |
312 return tmpl('error', error=err.message or '') | 312 return tmpl('error', error=err.message or '') |
313 finally: | 313 finally: |
314 tmpl = None | 314 tmpl = None |
315 | 315 |
316 def makeindex(self, req, tmpl, subdir=""): | 316 def makeindex(self, wsgireq, tmpl, subdir=""): |
317 | 317 |
318 def archivelist(ui, nodeid, url): | 318 def archivelist(ui, nodeid, url): |
319 allowed = ui.configlist("web", "allow_archive", untrusted=True) | 319 allowed = ui.configlist("web", "allow_archive", untrusted=True) |
320 archives = [] | 320 archives = [] |
321 for typ, spec in hgweb_mod.archivespecs.iteritems(): | 321 for typ, spec in hgweb_mod.archivespecs.iteritems(): |
367 except (IOError, error.RepoError): | 367 except (IOError, error.RepoError): |
368 pass | 368 pass |
369 | 369 |
370 parts = [name] | 370 parts = [name] |
371 parts.insert(0, '/' + subdir.rstrip('/')) | 371 parts.insert(0, '/' + subdir.rstrip('/')) |
372 if req.env['SCRIPT_NAME']: | 372 if wsgireq.env['SCRIPT_NAME']: |
373 parts.insert(0, req.env['SCRIPT_NAME']) | 373 parts.insert(0, wsgireq.env['SCRIPT_NAME']) |
374 url = re.sub(r'/+', '/', '/'.join(parts) + '/') | 374 url = re.sub(r'/+', '/', '/'.join(parts) + '/') |
375 | 375 |
376 # show either a directory entry or a repository | 376 # show either a directory entry or a repository |
377 if directory: | 377 if directory: |
378 # get the directory's time information | 378 # get the directory's time information |
411 return u.config(section, name, default, untrusted=True) | 411 return u.config(section, name, default, untrusted=True) |
412 | 412 |
413 if u.configbool("web", "hidden", untrusted=True): | 413 if u.configbool("web", "hidden", untrusted=True): |
414 continue | 414 continue |
415 | 415 |
416 if not self.read_allowed(u, req): | 416 if not self.read_allowed(u, wsgireq): |
417 continue | 417 continue |
418 | 418 |
419 # update time with local timezone | 419 # update time with local timezone |
420 try: | 420 try: |
421 r = hg.repository(self.ui, path) | 421 r = hg.repository(self.ui, path) |
463 yield row | 463 yield row |
464 | 464 |
465 self.refresh() | 465 self.refresh() |
466 sortable = ["name", "description", "contact", "lastchange"] | 466 sortable = ["name", "description", "contact", "lastchange"] |
467 sortcolumn, descending = sortdefault | 467 sortcolumn, descending = sortdefault |
468 if 'sort' in req.form: | 468 if 'sort' in wsgireq.form: |
469 sortcolumn = req.form['sort'][0] | 469 sortcolumn = wsgireq.form['sort'][0] |
470 descending = sortcolumn.startswith('-') | 470 descending = sortcolumn.startswith('-') |
471 if descending: | 471 if descending: |
472 sortcolumn = sortcolumn[1:] | 472 sortcolumn = sortcolumn[1:] |
473 if sortcolumn not in sortable: | 473 if sortcolumn not in sortable: |
474 sortcolumn = "" | 474 sortcolumn = "" |
477 "%s%s" % ((not descending and column == sortcolumn) | 477 "%s%s" % ((not descending and column == sortcolumn) |
478 and "-" or "", column)) | 478 and "-" or "", column)) |
479 for column in sortable] | 479 for column in sortable] |
480 | 480 |
481 self.refresh() | 481 self.refresh() |
482 self.updatereqenv(req.env) | 482 self.updatereqenv(wsgireq.env) |
483 | 483 |
484 return tmpl("index", entries=entries, subdir=subdir, | 484 return tmpl("index", entries=entries, subdir=subdir, |
485 pathdef=hgweb_mod.makebreadcrumb('/' + subdir, self.prefix), | 485 pathdef=hgweb_mod.makebreadcrumb('/' + subdir, self.prefix), |
486 sortcolumn=sortcolumn, descending=descending, | 486 sortcolumn=sortcolumn, descending=descending, |
487 **dict(sort)) | 487 **dict(sort)) |
488 | 488 |
489 def templater(self, req, nonce): | 489 def templater(self, wsgireq, nonce): |
490 | 490 |
491 def motd(**map): | 491 def motd(**map): |
492 if self.motd is not None: | 492 if self.motd is not None: |
493 yield self.motd | 493 yield self.motd |
494 else: | 494 else: |
495 yield config('web', 'motd') | 495 yield config('web', 'motd') |
496 | 496 |
497 def config(section, name, default=uimod._unset, untrusted=True): | 497 def config(section, name, default=uimod._unset, untrusted=True): |
498 return self.ui.config(section, name, default, untrusted) | 498 return self.ui.config(section, name, default, untrusted) |
499 | 499 |
500 self.updatereqenv(req.env) | 500 self.updatereqenv(wsgireq.env) |
501 | 501 |
502 url = req.env.get('SCRIPT_NAME', '') | 502 url = wsgireq.env.get('SCRIPT_NAME', '') |
503 if not url.endswith('/'): | 503 if not url.endswith('/'): |
504 url += '/' | 504 url += '/' |
505 | 505 |
506 vars = {} | 506 vars = {} |
507 styles, (style, mapfile) = hgweb_mod.getstyle(req, config, | 507 styles, (style, mapfile) = hgweb_mod.getstyle(wsgireq, config, |
508 self.templatepath) | 508 self.templatepath) |
509 if style == styles[0]: | 509 if style == styles[0]: |
510 vars['style'] = style | 510 vars['style'] = style |
511 | 511 |
512 start = r'&' if url[-1] == r'?' else r'?' | 512 start = r'&' if url[-1] == r'?' else r'?' |