diff -r b2a3308d6a21 -r d7fd203e36cc mercurial/hgweb/request.py --- a/mercurial/hgweb/request.py Sun Mar 11 12:53:47 2018 -0700 +++ b/mercurial/hgweb/request.py Sun Mar 11 13:11:13 2018 -0700 @@ -155,11 +155,16 @@ # Request body input stream. bodyfh = attr.ib() -def parserequestfromenv(env, bodyfh): +def parserequestfromenv(env, bodyfh, reponame=None): """Parse URL components from environment variables. WSGI defines request attributes via environment variables. This function parses the environment variables into a data structure. + + If ``reponame`` is defined, the leading path components matching that + string are effectively shifted from ``PATH_INFO`` to ``SCRIPT_NAME``. + This simulates the world view of a WSGI application that processes + requests from the base URL of a repo. """ # PEP-0333 defines the WSGI spec and is a useful reference for this code. @@ -215,28 +220,34 @@ fullurl += '?' + env['QUERY_STRING'] advertisedfullurl += '?' + env['QUERY_STRING'] - # When dispatching requests, we look at the URL components (PATH_INFO - # and QUERY_STRING) after the application root (SCRIPT_NAME). But hgwebdir - # has the concept of "virtual" repositories. This is defined via REPO_NAME. - # If REPO_NAME is defined, we append it to SCRIPT_NAME to form a new app - # root. We also exclude its path components from PATH_INFO when resolving - # the dispatch path. + # If ``reponame`` is defined, that must be a prefix on PATH_INFO + # that represents the repository being dispatched to. When computing + # the dispatch info, we ignore these leading path components. apppath = env.get('SCRIPT_NAME', '') - if env.get('REPO_NAME'): - if not apppath.endswith('/'): - apppath += '/' + if reponame: + repoprefix = '/' + reponame.strip('/') - apppath += env.get('REPO_NAME') + if not env.get('PATH_INFO'): + raise error.ProgrammingError('reponame requires PATH_INFO') + + if not env['PATH_INFO'].startswith(repoprefix): + raise error.ProgrammingError('PATH_INFO does not begin with repo ' + 'name: %s (%s)' % (env['PATH_INFO'], + reponame)) - if 'PATH_INFO' in env: - dispatchparts = env['PATH_INFO'].strip('/').split('/') + dispatchpath = env['PATH_INFO'][len(repoprefix):] - # Strip out repo parts. - repoparts = env.get('REPO_NAME', '').split('/') - if dispatchparts[:len(repoparts)] == repoparts: - dispatchparts = dispatchparts[len(repoparts):] + if dispatchpath and not dispatchpath.startswith('/'): + raise error.ProgrammingError('reponame prefix of PATH_INFO does ' + 'not end at path delimiter: %s (%s)' % + (env['PATH_INFO'], reponame)) + + apppath = apppath.rstrip('/') + repoprefix + dispatchparts = dispatchpath.strip('/').split('/') + elif env.get('PATH_INFO', '').strip('/'): + dispatchparts = env['PATH_INFO'].strip('/').split('/') else: dispatchparts = [] @@ -283,7 +294,7 @@ apppath=apppath, dispatchparts=dispatchparts, dispatchpath=dispatchpath, havepathinfo='PATH_INFO' in env, - reponame=env.get('REPO_NAME'), + reponame=reponame, querystring=querystring, qsparams=qsparams, headers=headers,