##// END OF EJS Templates
hgweb: rename req to wsgireq...
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

File last commit:

r36822:b9b968e2 default
r36822:b9b968e2 default
Show More
hgweb_mod.py
473 lines | 16.9 KiB | text/x-python | PythonLexer
Eric Hopper
Fixing up comment headers for split up code.
r2391 # hgweb/hgweb_mod.py - Web interface for a repository.
Eric Hopper
Final stage of the hgweb split up....
r2356 #
# Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
Thomas Arendsen Hein
Updated copyright notices and add "and others" to "hg version"
r4635 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
Eric Hopper
Final stage of the hgweb split up....
r2356 #
Martin Geisler
updated license to be explicit about GPL version 2
r8225 # This software may be used and distributed according to the terms of the
Matt Mackall
Update license to GPLv2+
r10263 # GNU General Public License version 2 or any later version.
Eric Hopper
Final stage of the hgweb split up....
r2356
Yuya Nishihara
hgweb: use absolute_import
r27046 from __future__ import absolute_import
Gregory Szorc
hgweb: use separate repo instances per thread...
r26220 import contextlib
Gregory Szorc
hgweb: extract web substitutions table generation to own function...
r26162 import os
Yuya Nishihara
hgweb: use absolute_import
r27046
from .common import (
ErrorResponse,
HTTP_BAD_REQUEST,
HTTP_NOT_FOUND,
HTTP_NOT_MODIFIED,
HTTP_OK,
HTTP_SERVER_ERROR,
caching,
Gregory Szorc
hgweb: support Content Security Policy...
r30766 cspvalues,
Yuya Nishihara
hgweb: use absolute_import
r27046 permhooks,
)
from .. import (
encoding,
error,
Yuya Nishihara
hgweb: make templater mostly compatible with log templates...
r36535 formatter,
Yuya Nishihara
hgweb: use absolute_import
r27046 hg,
hook,
Gregory Szorc
hgweb: profile HTTP requests...
r29787 profiling,
Augie Fackler
hgweb: extract function for loading style from request context...
r34516 pycompat,
Yuya Nishihara
hgweb: use absolute_import
r27046 repoview,
templatefilters,
templater,
ui as uimod,
util,
Gregory Szorc
wireprotoserver: rename hgweb.protocol to wireprotoserver (API)...
r35874 wireprotoserver,
Yuya Nishihara
hgweb: use absolute_import
r27046 )
from . import (
Gregory Szorc
hgweb: rename req to wsgireq...
r36822 request as requestmod,
Yuya Nishihara
hgweb: use absolute_import
r27046 webcommands,
webutil,
wsgicgi,
)
Eric Hopper
Final stage of the hgweb split up....
r2356
av6
hgweb: use archivespecs for links on repo index page too...
r30749 archivespecs = util.sortdict((
('zip', ('application/zip', 'zip', '.zip', None)),
('gz', ('application/x-gzip', 'tgz', '.tar.gz', None)),
('bz2', ('application/x-bzip2', 'tbz2', '.tar.bz2', None)),
))
Augie Fackler
hgweb: extract function for loading style from request context...
r34516 def getstyle(req, configfn, templatepath):
fromreq = req.form.get('style', [None])[0]
styles = (
fromreq,
configfn('web', 'style'),
'paper',
)
return styles, templater.stylemap(styles, templatepath)
Angel Ezquerra
hgwebdir: use web.prefix when creating url breadcrumbs (issue3790)...
r18515 def makebreadcrumb(url, prefix=''):
Angel Ezquerra <angel.ezquerra at gmail.com>
hgweb: add a "URL breadcrumb" to the index and repository pages...
r18258 '''Return a 'URL breadcrumb' list
A 'URL breadcrumb' is a list of URL-name pairs,
corresponding to each of the path items on a URL.
This can be used to create path navigation entries.
'''
if url.endswith('/'):
url = url[:-1]
Angel Ezquerra
hgwebdir: use web.prefix when creating url breadcrumbs (issue3790)...
r18515 if prefix:
url = '/' + prefix + url
Angel Ezquerra <angel.ezquerra at gmail.com>
hgweb: add a "URL breadcrumb" to the index and repository pages...
r18258 relpath = url
if relpath.startswith('/'):
relpath = relpath[1:]
breadcrumb = []
urlel = url
pathitems = [''] + relpath.split('/')
for pathel in reversed(pathitems):
if not pathel or not urlel:
break
breadcrumb.append({'url': urlel, 'name': pathel})
urlel = os.path.dirname(urlel)
return reversed(breadcrumb)
Gregory Szorc
hgweb: establish class for holding per request context...
r26134 class requestcontext(object):
"""Holds state/context for an individual request.
Servers can be multi-threaded. Holding state on the WSGI application
is prone to race conditions. Instances of this class exist to hold
mutable and race-free state for requests.
"""
Gregory Szorc
hg: establish a cache for localrepository instances...
r26219 def __init__(self, app, repo):
self.repo = repo
Gregory Szorc
hgweb: remove proxy to hgweb instance...
r26217 self.reponame = app.reponame
Gregory Szorc
hgweb: establish class for holding per request context...
r26134
av6
hgweb: use archivespecs for links on repo index page too...
r30749 self.archivespecs = archivespecs
Boris Feld
configitems: register the 'web.maxchanges' config
r34591 self.maxchanges = self.configint('web', 'maxchanges')
Boris Feld
configitems: register the 'web.stripes' config
r34242 self.stripecount = self.configint('web', 'stripes')
Boris Feld
configitems: register the 'web.maxshortchanges' config
r34589 self.maxshortchanges = self.configint('web', 'maxshortchanges')
Boris Feld
configitems: register the 'web.maxfiles' config
r34590 self.maxfiles = self.configint('web', 'maxfiles')
David Demelier
config: rename allowpull to allow-pull...
r35028 self.allowpull = self.configbool('web', 'allow-pull')
Gregory Szorc
hgweb: move some config options to requestcontext...
r26135
Gregory Szorc
hgweb: move templatepath to requestcontext...
r26163 # we use untrusted=False to prevent a repo owner from using
# web.templates in .hg/hgrc to get access to any file readable
# by the user running the CGI script
Gregory Szorc
hgweb: remove proxy to hgweb instance...
r26217 self.templatepath = self.config('web', 'templates', untrusted=False)
Gregory Szorc
hgweb: move templatepath to requestcontext...
r26163
Gregory Szorc
hgweb: create websubtable on requestcontext
r26164 # This object is more expensive to build than simple config values.
# It is shared across requests. The app will replace the object
# if it is updated. Since this is a reference and nothing should
# modify the underlying object, it should be constant for the lifetime
# of the request.
Gregory Szorc
hgweb: remove proxy to hgweb instance...
r26217 self.websubtable = app.websubtable
Gregory Szorc
hgweb: create websubtable on requestcontext
r26164
Gregory Szorc
hgweb: support Content Security Policy...
r30766 self.csp, self.nonce = cspvalues(self.repo.ui)
Gregory Szorc
hgweb: move some config options to requestcontext...
r26135 # Trust the settings from the .hg/hgrc files by default.
David Demelier
hgweb: use ui._unset to prevent a warning in configitems
r33328 def config(self, section, name, default=uimod._unset, untrusted=True):
Gregory Szorc
hgweb: move some config options to requestcontext...
r26135 return self.repo.ui.config(section, name, default,
untrusted=untrusted)
David Demelier
hgweb: use ui._unset to prevent a warning in configitems
r33328 def configbool(self, section, name, default=uimod._unset, untrusted=True):
Gregory Szorc
hgweb: move some config options to requestcontext...
r26135 return self.repo.ui.configbool(section, name, default,
untrusted=untrusted)
David Demelier
hgweb: use ui._unset to prevent a warning in configitems
r33328 def configint(self, section, name, default=uimod._unset, untrusted=True):
Gregory Szorc
hgweb: move some config options to requestcontext...
r26135 return self.repo.ui.configint(section, name, default,
untrusted=untrusted)
David Demelier
hgweb: use ui._unset to prevent a warning in configitems
r33328 def configlist(self, section, name, default=uimod._unset, untrusted=True):
Gregory Szorc
hgweb: move some config options to requestcontext...
r26135 return self.repo.ui.configlist(section, name, default,
untrusted=untrusted)
Gregory Szorc
hgweb: move archive related attributes to requestcontext...
r26136 def archivelist(self, nodeid):
allowed = self.configlist('web', 'allow_archive')
av6
hgweb: use util.sortdict for archivespecs...
r30748 for typ, spec in self.archivespecs.iteritems():
Gregory Szorc
hgweb: move archive related attributes to requestcontext...
r26136 if typ in allowed or self.configbool('web', 'allow%s' % typ):
yield {'type': typ, 'extension': spec[2], 'node': nodeid}
Angel Ezquerra <angel.ezquerra at gmail.com>
hgweb: add a "URL breadcrumb" to the index and repository pages...
r18258
Gregory Szorc
hgweb: rename req to wsgireq...
r36822 def templater(self, wsgireq):
Gregory Szorc
hgweb: move templater instantiation to requestcontext...
r26183 # determine scheme, port and server name
# this is needed to create absolute urls
Gregory Szorc
hgweb: rename req to wsgireq...
r36822 proto = wsgireq.env.get('wsgi.url_scheme')
Gregory Szorc
hgweb: move templater instantiation to requestcontext...
r26183 if proto == 'https':
proto = 'https'
default_port = '443'
else:
proto = 'http'
default_port = '80'
Gregory Szorc
hgweb: rename req to wsgireq...
r36822 port = wsgireq.env[r'SERVER_PORT']
Augie Fackler
hgweb: rewrite most obviously-native-strings to be native strings...
r34705 port = port != default_port and (r':' + port) or r''
Gregory Szorc
hgweb: rename req to wsgireq...
r36822 urlbase = r'%s://%s%s' % (proto, wsgireq.env[r'SERVER_NAME'], port)
Boris Feld
configitems: register the 'web.logourl' config
r34613 logourl = self.config('web', 'logourl')
Boris Feld
configitems: register the 'web.logoimg' config
r34612 logoimg = self.config('web', 'logoimg')
Gregory Szorc
hgweb: ensure all wsgi environment values are str...
r36820 staticurl = (self.config('web', 'staticurl')
Gregory Szorc
hgweb: rename req to wsgireq...
r36822 or pycompat.sysbytes(wsgireq.url) + 'static/')
Gregory Szorc
hgweb: move templater instantiation to requestcontext...
r26183 if not staticurl.endswith('/'):
staticurl += '/'
# some functions for the templater
def motd(**map):
Boris Feld
configitems: register the 'web.motd' config
r34588 yield self.config('web', 'motd')
Gregory Szorc
hgweb: move templater instantiation to requestcontext...
r26183
# figure out which style to use
vars = {}
Gregory Szorc
hgweb: rename req to wsgireq...
r36822 styles, (style, mapfile) = getstyle(wsgireq, self.config,
Augie Fackler
hgweb: extract function for loading style from request context...
r34516 self.templatepath)
Gregory Szorc
hgweb: move templater instantiation to requestcontext...
r26183 if style == styles[0]:
vars['style'] = style
Gregory Szorc
hgweb: rename req to wsgireq...
r36822 start = '&' if wsgireq.url[-1] == r'?' else '?'
Gregory Szorc
hgweb: move templater instantiation to requestcontext...
r26183 sessionvars = webutil.sessionvars(vars, start)
if not self.reponame:
Boris Feld
configitems: register the 'web.name' config
r34587 self.reponame = (self.config('web', 'name', '')
Gregory Szorc
hgweb: rename req to wsgireq...
r36822 or wsgireq.env.get('REPO_NAME')
or wsgireq.url.strip(r'/') or self.repo.root)
Gregory Szorc
hgweb: move templater instantiation to requestcontext...
r26183
def websubfilter(text):
Yuya Nishihara
hgweb: do not import templatefilters.revescape and websub as symbol...
r27008 return templatefilters.websub(text, self.websubtable)
Gregory Szorc
hgweb: move templater instantiation to requestcontext...
r26183
# create the templater
Yuya Nishihara
hgweb: make templater mostly compatible with log templates...
r36535 # TODO: export all keywords: defaults = templatekw.keywords.copy()
Yuya Nishihara
templater: separate function to create templater from map file (API)...
r28954 defaults = {
Gregory Szorc
hgweb: rename req to wsgireq...
r36822 'url': pycompat.sysbytes(wsgireq.url),
Yuya Nishihara
templater: separate function to create templater from map file (API)...
r28954 'logourl': logourl,
'logoimg': logoimg,
'staticurl': staticurl,
'urlbase': urlbase,
'repo': self.reponame,
'encoding': encoding.encoding,
'motd': motd,
'sessionvars': sessionvars,
Gregory Szorc
hgweb: rename req to wsgireq...
r36822 'pathdef': makebreadcrumb(pycompat.sysbytes(wsgireq.url)),
Yuya Nishihara
templater: separate function to create templater from map file (API)...
r28954 'style': style,
Gregory Szorc
hgweb: support Content Security Policy...
r30766 'nonce': self.nonce,
Yuya Nishihara
templater: separate function to create templater from map file (API)...
r28954 }
Yuya Nishihara
hgweb: make templater mostly compatible with log templates...
r36535 tres = formatter.templateresources(self.repo.ui, self.repo)
Yuya Nishihara
templater: separate function to create templater from map file (API)...
r28954 tmpl = templater.templater.frommapfile(mapfile,
filters={'websub': websubfilter},
Yuya Nishihara
hgweb: make templater mostly compatible with log templates...
r36535 defaults=defaults,
resources=tres)
Gregory Szorc
hgweb: move templater instantiation to requestcontext...
r26183 return tmpl
Eric Hopper
Final stage of the hgweb split up....
r2356 class hgweb(object):
Gregory Szorc
hgweb: add some documentation...
r26132 """HTTP server for individual repositories.
Instances of this class serve HTTP responses for a particular
repository.
Instances are typically used as WSGI applications.
Some servers are multi-threaded. On these servers, there may
be multiple active threads inside __call__.
"""
Matt Mackall
hgweb: add baseui to hgweb entrypoint
r10994 def __init__(self, repo, name=None, baseui=None):
Christian Ebert
Use isinstance instead of type == type
r4874 if isinstance(repo, str):
Matt Mackall
hgweb: add baseui to hgweb entrypoint
r10994 if baseui:
u = baseui.copy()
else:
Yuya Nishihara
ui: factor out ui.load() to create a ui without loading configs (API)...
r30559 u = uimod.ui.load()
Matt Mackall
hgweb: avoid initialization race (issue3953)
r20168 r = hg.repository(u, repo)
Eric Hopper
Final stage of the hgweb split up....
r2356 else:
Matt Mackall
hgweb: avoid config object race with hgwebdir (issue4326)...
r22087 # we trust caller to give us a private copy
Matt Mackall
hgweb: avoid initialization race (issue3953)
r20168 r = repo
Eric Hopper
Final stage of the hgweb split up....
r2356
Mads Kiilerich
config: set a 'source' in most cases where config don't come from file but code...
r20790 r.ui.setconfig('ui', 'report_untrusted', 'off', 'hgweb')
r.baseui.setconfig('ui', 'report_untrusted', 'off', 'hgweb')
r.ui.setconfig('ui', 'nontty', 'true', 'hgweb')
r.baseui.setconfig('ui', 'nontty', 'true', 'hgweb')
Yuya Nishihara
hgweb: overwrite cwd to resolve file patterns relative to repo (issue4568)...
r26294 # resolve file patterns relative to repo root
r.ui.setconfig('ui', 'forcecwd', r.root, 'hgweb')
r.baseui.setconfig('ui', 'forcecwd', r.root, 'hgweb')
Pierre-Yves David
hgewb: disable progress when serving (issue4582)...
r25488 # displaying bundling progress bar while serving feel wrong and may
# break some wsgi implementation.
r.ui.setconfig('progress', 'disable', 'true', 'hgweb')
r.baseui.setconfig('progress', 'disable', 'true', 'hgweb')
Gregory Szorc
hgweb: use separate repo instances per thread...
r26220 self._repos = [hg.cachedlocalrepo(self._webifyrepo(r))]
self._lastrepo = self._repos[0]
Matt Mackall
hook: redirect stdout to stderr for ssh and http servers
r5833 hook.redirect(True)
Eric Hopper
Final stage of the hgweb split up....
r2356 self.reponame = name
Alexis S. L. Carvalho
use untrusted settings in hgweb...
r3555
Gregory Szorc
hgweb: create function to perform actions on new repo...
r26218 def _webifyrepo(self, repo):
repo = getwebview(repo)
self.websubtable = webutil.getwebsubs(repo)
return repo
Gregory Szorc
hgweb: use separate repo instances per thread...
r26220 @contextlib.contextmanager
def _obtainrepo(self):
"""Obtain a repo unique to the caller.
Internally we maintain a stack of cachedlocalrepo instances
to be handed out. If one is available, we pop it and return it,
ensuring it is up to date in the process. If one is not available,
we clone the most recently used repo instance and return it.
Gregory Szorc
hg: establish a cache for localrepository instances...
r26219
Gregory Szorc
hgweb: use separate repo instances per thread...
r26220 It is currently possible for the stack to grow without bounds
if the server allows infinite threads. However, servers should
have a thread limit, thus establishing our limit.
"""
if self._repos:
cached = self._repos.pop()
r, created = cached.fetch()
else:
cached = self._lastrepo.copy()
r, created = cached.fetch()
Gregory Szorc
hg: always create new localrepository instance...
r26240 if created:
r = self._webifyrepo(r)
Gregory Szorc
hgweb: use separate repo instances per thread...
r26220
self._lastrepo = cached
self.mtime = cached.mtime
try:
yield r
finally:
self._repos.append(cached)
Eric Hopper
Final stage of the hgweb split up....
r2356
Dirkjan Ochtman
split out hgweb commands into a separate file, move some code around
r5591 def run(self):
Gregory Szorc
hgweb: add some documentation...
r26132 """Start a server from CGI environment.
Modern servers should be using WSGI and should avoid this
method, if possible.
"""
Pulkit Goyal
py3: replace os.environ with encoding.environ (part 3 of 5)
r30636 if not encoding.environ.get('GATEWAY_INTERFACE',
'').startswith("CGI/1."):
Martin Geisler
wrap string literals in error messages
r8663 raise RuntimeError("This function is only intended to be "
"called while running as a CGI script.")
Dirkjan Ochtman
split out hgweb commands into a separate file, move some code around
r5591 wsgicgi.launch(self)
def __call__(self, env, respond):
Gregory Szorc
hgweb: add some documentation...
r26132 """Run the WSGI application.
This may be called by multiple threads.
"""
Gregory Szorc
hgweb: rename req to wsgireq...
r36822 req = requestmod.wsgirequest(env, respond)
Dirkjan Ochtman
hgweb: all protocol functions have become generators...
r6784 return self.run_wsgi(req)
Dirkjan Ochtman
split out hgweb commands into a separate file, move some code around
r5591
Gregory Szorc
hgweb: rename req to wsgireq...
r36822 def run_wsgi(self, wsgireq):
Gregory Szorc
hgweb: add some documentation...
r26132 """Internal method to run the WSGI application.
Dirkjan Ochtman
split out hgweb commands into a separate file, move some code around
r5591
Gregory Szorc
hgweb: add some documentation...
r26132 This is typically only called by Mercurial. External consumers
should be using instances of this class as the WSGI application.
"""
Gregory Szorc
hgweb: use separate repo instances per thread...
r26220 with self._obtainrepo() as repo:
profile: drop maybeprofile...
r32788 profile = repo.ui.configbool('profiling', 'enabled')
with profiling.profile(repo.ui, enabled=profile):
Gregory Szorc
hgweb: rename req to wsgireq...
r36822 for r in self._runwsgi(wsgireq, repo):
Gregory Szorc
hgweb: profile HTTP requests...
r29787 yield r
Gregory Szorc
hgweb: use separate repo instances per thread...
r26220
Gregory Szorc
hgweb: rename req to wsgireq...
r36822 def _runwsgi(self, wsgireq, repo):
Gregory Szorc
hg: establish a cache for localrepository instances...
r26219 rctx = requestcontext(self, repo)
Dirkjan Ochtman
split out hgweb commands into a separate file, move some code around
r5591
Gregory Szorc
hgweb: move additional state setting outside of refresh...
r26160 # This state is global across all threads.
Boris Feld
configitems: register the 'web.encoding' config
r34236 encoding.encoding = rctx.config('web', 'encoding')
Gregory Szorc
hgweb: rename req to wsgireq...
r36822 rctx.repo.ui.environ = wsgireq.env
Dirkjan Ochtman
split out hgweb commands into a separate file, move some code around
r5591
Gregory Szorc
hgweb: support Content Security Policy...
r30766 if rctx.csp:
# hgwebdir may have added CSP header. Since we generate our own,
# replace it.
Gregory Szorc
hgweb: rename req to wsgireq...
r36822 wsgireq.headers = [h for h in wsgireq.headers
if h[0] != 'Content-Security-Policy']
wsgireq.headers.append(('Content-Security-Policy', rctx.csp))
Gregory Szorc
hgweb: support Content Security Policy...
r30766
Dirkjan Ochtman
hgweb: get rid of some nested functions
r5596 # work with CGI variables to create coherent structure
# use SCRIPT_NAME, PATH_INFO and QUERY_STRING as well as our REPO_NAME
Dirkjan Ochtman
split out hgweb commands into a separate file, move some code around
r5591
Gregory Szorc
hgweb: rename req to wsgireq...
r36822 wsgireq.url = wsgireq.env[r'SCRIPT_NAME']
if not wsgireq.url.endswith(r'/'):
wsgireq.url += r'/'
if wsgireq.env.get('REPO_NAME'):
wsgireq.url += wsgireq.env[r'REPO_NAME'] + r'/'
Dirkjan Ochtman
split out hgweb commands into a separate file, move some code around
r5591
Gregory Szorc
hgweb: rename req to wsgireq...
r36822 if r'PATH_INFO' in wsgireq.env:
parts = wsgireq.env[r'PATH_INFO'].strip(r'/').split(r'/')
repo_parts = wsgireq.env.get(r'REPO_NAME', r'').split(r'/')
Dirkjan Ochtman
hgweb: get rid of some nested functions
r5596 if parts[:len(repo_parts)] == repo_parts:
parts = parts[len(repo_parts):]
Gregory Szorc
hgweb: ensure all wsgi environment values are str...
r36820 query = r'/'.join(parts)
Dirkjan Ochtman
hgweb: get rid of some nested functions
r5596 else:
Gregory Szorc
hgweb: rename req to wsgireq...
r36822 query = wsgireq.env[r'QUERY_STRING'].partition(r'&')[0]
Augie Fackler
hgweb: rewrite most obviously-native-strings to be native strings...
r34705 query = query.partition(r';')[0]
Dirkjan Ochtman
split out hgweb commands into a separate file, move some code around
r5591
Gregory Szorc
wireprotoserver: move protocol parsing and dispatch out of hgweb...
r36002 # Route it to a wire protocol handler if it looks like a wire protocol
# request.
Gregory Szorc
hgweb: rename req to wsgireq...
r36822 protohandler = wireprotoserver.parsehttprequest(rctx, wsgireq, query,
Gregory Szorc
wireproto: formalize permissions checking as part of protocol interface...
r36819 self.check_perm)
Benoit Boissinot
hgweb: deny cloning a subpath of a repo
r8860
Gregory Szorc
wireprotoserver: move protocol parsing and dispatch out of hgweb...
r36002 if protohandler:
Mads Kiilerich
hgweb: handle invalid requests with both form data and querystring...
r13445 try:
if query:
raise ErrorResponse(HTTP_NOT_FOUND)
Gregory Szorc
wireproto: check permissions when executing "batch" command (BC) (SEC)...
r36773
Gregory Szorc
wireproto: formalize permissions checking as part of protocol interface...
r36819 return protohandler['dispatch']()
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except ErrorResponse as inst:
Gregory Szorc
wireprotoserver: move error response handling out of hgweb...
r36004 return protohandler['handleerror'](inst)
Benoit Boissinot
hgweb: deny cloning a subpath of a repo
r8860
Dirkjan Ochtman
hgweb: get rid of some nested functions
r5596 # translate user-visible url structure to internal structure
Gregory Szorc
hgweb: ensure all wsgi environment values are str...
r36820 args = query.split(r'/', 2)
Gregory Szorc
hgweb: rename req to wsgireq...
r36822 if 'cmd' not in wsgireq.form and args and args[0]:
Dirkjan Ochtman
split out hgweb commands into a separate file, move some code around
r5591 cmd = args.pop(0)
style = cmd.rfind('-')
if style != -1:
Gregory Szorc
hgweb: rename req to wsgireq...
r36822 wsgireq.form['style'] = [cmd[:style]]
Matt Mackall
many, many trivial check-code fixups
r10282 cmd = cmd[style + 1:]
Dirkjan Ochtman
hgweb: get rid of some nested functions
r5596
Dirkjan Ochtman
split out hgweb commands into a separate file, move some code around
r5591 # avoid accepting e.g. style parameter as command
Augie Fackler
hgweb_mod: use safehasattr instead of hasattr
r14953 if util.safehasattr(webcommands, cmd):
Gregory Szorc
hgweb: rename req to wsgireq...
r36822 wsgireq.form['cmd'] = [cmd]
Dirkjan Ochtman
split out hgweb commands into a separate file, move some code around
r5591
Brendan Cully
hgweb: handle subdirectories within static directory
r7287 if cmd == 'static':
Gregory Szorc
hgweb: rename req to wsgireq...
r36822 wsgireq.form['file'] = ['/'.join(args)]
Brendan Cully
hgweb: handle subdirectories within static directory
r7287 else:
if args and args[0]:
av6
hgweb: allow symbolic revisions with forward slashes in urls...
r25777 node = args.pop(0).replace('%2F', '/')
Gregory Szorc
hgweb: rename req to wsgireq...
r36822 wsgireq.form['node'] = [node]
Brendan Cully
hgweb: handle subdirectories within static directory
r7287 if args:
Gregory Szorc
hgweb: rename req to wsgireq...
r36822 wsgireq.form['file'] = args
Dirkjan Ochtman
split out hgweb commands into a separate file, move some code around
r5591
Gregory Szorc
hgweb: rename req to wsgireq...
r36822 ua = wsgireq.env.get('HTTP_USER_AGENT', '')
Dirkjan Ochtman
hgweb: treat rev as raw-rev if user agent is hg
r9731 if cmd == 'rev' and 'mercurial' in ua:
Gregory Szorc
hgweb: rename req to wsgireq...
r36822 wsgireq.form['style'] = ['raw']
Dirkjan Ochtman
hgweb: treat rev as raw-rev if user agent is hg
r9731
Brendan Cully
hgweb: handle subdirectories within static directory
r7287 if cmd == 'archive':
Gregory Szorc
hgweb: rename req to wsgireq...
r36822 fn = wsgireq.form['node'][0]
Gregory Szorc
hgweb: move archive related attributes to requestcontext...
r26136 for type_, spec in rctx.archivespecs.iteritems():
Dirkjan Ochtman
split out hgweb commands into a separate file, move some code around
r5591 ext = spec[2]
if fn.endswith(ext):
Gregory Szorc
hgweb: rename req to wsgireq...
r36822 wsgireq.form['node'] = [fn[:-len(ext)]]
wsgireq.form['type'] = [type_]
Gregory Szorc
wireprotoserver: move protocol parsing and dispatch out of hgweb...
r36002 else:
Gregory Szorc
hgweb: rename req to wsgireq...
r36822 cmd = wsgireq.form.get('cmd', [''])[0]
Dirkjan Ochtman
split out hgweb commands into a separate file, move some code around
r5591
Dirkjan Ochtman
hgweb: separate protocol calls from interface calls (issue996)...
r6149 # process the web interface request
Dirkjan Ochtman
hgweb: split out templater definition
r5599
try:
Gregory Szorc
hgweb: rename req to wsgireq...
r36822 tmpl = rctx.templater(wsgireq)
Matt Mackall
hgweb: web.encoding should override encoding.encoding (issue1183)
r8859 ctype = tmpl('mimetype', encoding=encoding.encoding)
Dirkjan Ochtman
Backed out changeset d2bb66a8a435 (temporary template compatibility)
r6391 ctype = templater.stringify(ctype)
Dirkjan Ochtman
hgweb: separate protocol calls from interface calls (issue996)...
r6149
Mark Edgington
hgweb: allow static content when deny_read denies access
r7562 # check read permissions non-static content
if cmd != 'static':
Gregory Szorc
hgweb: rename req to wsgireq...
r36822 self.check_perm(rctx, wsgireq, None)
Mark Edgington
hgweb: support for deny_read/allow_read options...
r7336
Dirkjan Ochtman
hgweb: separate protocol calls from interface calls (issue996)...
r6149 if cmd == '':
Gregory Szorc
hgweb: rename req to wsgireq...
r36822 wsgireq.form['cmd'] = [tmpl.cache['default']]
cmd = wsgireq.form['cmd'][0]
Dirkjan Ochtman
hgweb: fast path for sending raw files
r5890
Gregory Szorc
hgweb: support Content Security Policy...
r30766 # Don't enable caching if using a CSP nonce because then it wouldn't
# be a nonce.
Boris Feld
configitems: register the 'web.cache' config
r34606 if rctx.configbool('web', 'cache') and not rctx.nonce:
Gregory Szorc
hgweb: rename req to wsgireq...
r36822 caching(self, wsgireq) # sets ETag header or raises NOT_MODIFIED
Dirkjan Ochtman
hgweb: separate protocol calls from interface calls (issue996)...
r6149 if cmd not in webcommands.__all__:
Dirkjan Ochtman
hgweb: better error messages
r6368 msg = 'no such method: %s' % cmd
Dirkjan Ochtman
hgweb: separate protocol calls from interface calls (issue996)...
r6149 raise ErrorResponse(HTTP_BAD_REQUEST, msg)
Gregory Szorc
hgweb: rename req to wsgireq...
r36822 elif cmd == 'file' and 'raw' in wsgireq.form.get('style', []):
Gregory Szorc
hgweb: remove proxy to hgweb instance...
r26217 rctx.ctype = ctype
Gregory Szorc
hgweb: rename req to wsgireq...
r36822 content = webcommands.rawfile(rctx, wsgireq, tmpl)
Dirkjan Ochtman
hgweb: separate protocol calls from interface calls (issue996)...
r6149 else:
Gregory Szorc
hgweb: rename req to wsgireq...
r36822 content = getattr(webcommands, cmd)(rctx, wsgireq, tmpl)
wsgireq.respond(HTTP_OK, ctype)
Dirkjan Ochtman
hgweb: fast path for sending raw files
r5890
Brendan Cully
templater: return data in increasing chunk sizes...
r7396 return content
Dirkjan Ochtman
hgweb: explicitly pass around the templater
r5600
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except (error.LookupError, error.RepoLookupError) as err:
Gregory Szorc
hgweb: rename req to wsgireq...
r36822 wsgireq.respond(HTTP_NOT_FOUND, ctype)
Augie Fackler
py3: get bytes-repr of network errors portably...
r36272 msg = pycompat.bytestr(err)
Takumi IINO
hgweb: show correct error message for i18n environment...
r18855 if (util.safehasattr(err, 'name') and
not isinstance(err, error.ManifestLookupError)):
Dirkjan Ochtman
hgweb: better error messages
r6368 msg = 'revision not found: %s' % err.name
Brendan Cully
templater: return data in increasing chunk sizes...
r7396 return tmpl('error', error=msg)
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except (error.RepoError, error.RevlogError) as inst:
Gregory Szorc
hgweb: rename req to wsgireq...
r36822 wsgireq.respond(HTTP_SERVER_ERROR, ctype)
Augie Fackler
py3: get bytes-repr of network errors portably...
r36272 return tmpl('error', error=pycompat.bytestr(inst))
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except ErrorResponse as inst:
Gregory Szorc
hgweb: rename req to wsgireq...
r36822 wsgireq.respond(inst, ctype)
Augie Fackler
hgweb: don't send a body or illegal headers during 304 response...
r12739 if inst.code == HTTP_NOT_MODIFIED:
# Not allowed to return a body on a 304
return ['']
Augie Fackler
py3: get bytes-repr of network errors portably...
r36272 return tmpl('error', error=pycompat.bytestr(inst))
Dirkjan Ochtman
hgweb: split out templater definition
r5599
Gregory Szorc
hgweb: establish class for holding per request context...
r26134 def check_perm(self, rctx, req, op):
Mads Kiilerich
cleanup: avoid local vars shadowing imports...
r22200 for permhook in permhooks:
Gregory Szorc
hgweb: establish class for holding per request context...
r26134 permhook(rctx, req, op)
Gregory Szorc
hgweb: extract _getview to own function...
r26208
def getwebview(repo):
"""The 'web.view' config controls changeset filter to hgweb. Possible
values are ``served``, ``visible`` and ``all``. Default is ``served``.
The ``served`` filter only shows changesets that can be pulled from the
hgweb instance. The``visible`` filter includes secret changesets but
still excludes "hidden" one.
See the repoview module for details.
The option has been around undocumented since Mercurial 2.5, but no
user ever asked about it. So we better keep it undocumented for now."""
Boris Feld
configitems: register the 'web.view' config
r34585 # experimental config: web.view
viewconfig = repo.ui.config('web', 'view', untrusted=True)
Gregory Szorc
hgweb: extract _getview to own function...
r26208 if viewconfig == 'all':
return repo.unfiltered()
elif viewconfig in repoview.filtertable:
return repo.filtered(viewconfig)
else:
return repo.filtered('served')