示例#1
0
    def run_wsgi(self, req):

        try:
            try:

                virtual = req.env.get("PATH_INFO", "").strip('/')
                tmpl = self.templater(req)
                try:
                    ctype = tmpl('mimetype', encoding=util._encoding)
                    ctype = templater.stringify(ctype)
                except KeyError:
                    # old templates with inline HTTP headers?
                    if 'mimetype' in tmpl:
                        raise
                    header = tmpl('header', encoding=util._encoding)
                    header_file = cStringIO.StringIO(
                        templater.stringify(header))
                    msg = mimetools.Message(header_file, 0)
                    ctype = msg['content-type']

                # a static file
                if virtual.startswith('static/') or 'static' in req.form:
                    static = os.path.join(templater.templatepath(), 'static')
                    if virtual.startswith('static/'):
                        fname = virtual[7:]
                    else:
                        fname = req.form['static'][0]
                    req.write(staticfile(static, fname, req))
                    return

                # top-level index
                elif not virtual:
                    req.respond(HTTP_OK, ctype)
                    req.write(self.makeindex(req, tmpl))
                    return

                # nested indexes and hgwebs

                repos = dict(self.repos)
                while virtual:
                    real = repos.get(virtual)
                    if real:
                        req.env['REPO_NAME'] = virtual
                        try:
                            repo = hg.repository(self.parentui, real)
                            hgweb(repo).run_wsgi(req)
                            return
                        except IOError, inst:
                            msg = inst.strerror
                            raise ErrorResponse(HTTP_SERVER_ERROR, msg)
                        except RepoError, inst:
                            raise ErrorResponse(HTTP_SERVER_ERROR, str(inst))
示例#2
0
    def run_wsgi(self, req):

        try:
            try:

                virtual = req.env.get("PATH_INFO", "").strip('/')
                tmpl = self.templater(req)
                try:
                    ctype = tmpl('mimetype', encoding=util._encoding)
                    ctype = templater.stringify(ctype)
                except KeyError:
                    # old templates with inline HTTP headers?
                    if 'mimetype' in tmpl:
                        raise
                    header = tmpl('header', encoding=util._encoding)
                    header_file = cStringIO.StringIO(templater.stringify(header))
                    msg = mimetools.Message(header_file, 0)
                    ctype = msg['content-type']

                # a static file
                if virtual.startswith('static/') or 'static' in req.form:
                    static = os.path.join(templater.templatepath(), 'static')
                    if virtual.startswith('static/'):
                        fname = virtual[7:]
                    else:
                        fname = req.form['static'][0]
                    req.write(staticfile(static, fname, req))
                    return

                # top-level index
                elif not virtual:
                    req.respond(HTTP_OK, ctype)
                    req.write(self.makeindex(req, tmpl))
                    return

                # nested indexes and hgwebs

                repos = dict(self.repos)
                while virtual:
                    real = repos.get(virtual)
                    if real:
                        req.env['REPO_NAME'] = virtual
                        try:
                            repo = hg.repository(self.parentui, real)
                            hgweb(repo).run_wsgi(req)
                            return
                        except IOError, inst:
                            msg = inst.strerror
                            raise ErrorResponse(HTTP_SERVER_ERROR, msg)
                        except RepoError, inst:
                            raise ErrorResponse(HTTP_SERVER_ERROR, str(inst))
示例#3
0
    def run(self):
        logging.info(self.request.headers['User-Agent'])
        url = urlparse(self.request.url)
        if len(url) > 1:
            self._baseurl = '%s://%s/' % (url[0], url[1])

        path = self.request.path_info
        repos_match = re.match("^/([^/]+)", path)
        if repos_match:
            # dispatch repositories
            repo_name = repos_match.group(1)
            if path == "/" + repo_name:
                # trailing slash is required.
                self.response.set_status(HTTP_MOVED_PERMANENTLY)
                target = "%s://%s%s/" % (url[0], url[1], url[2])
                if url[3]:
                    target += ";" + url[3]
                if url[4]:
                    target += "?" + url[4]
                self.response.headers["Location"] = target
                return
            code = self.dispatch(repo_name)
            self.response.set_status(code)
            return
        
        tmpl = self.templater()
        ctype = tmpl('mimetype', encoding="utf-8")
        ctype = templater.stringify(ctype)

        self.response.set_status(HTTP_OK)
        self.response.headers["Content-Type"] = ctype
        self.response.out.write(''.join(self.makeindex(tmpl)))
        return
示例#4
0
 def header(**map):
     header = tmpl('header', encoding=util._encoding, **map)
     if 'mimetype' not in tmpl:
         # old template with inline HTTP headers
         header_file = cStringIO.StringIO(templater.stringify(header))
         msg = mimetools.Message(header_file, 0)
         header = header_file.read()
     yield header
示例#5
0
 def header(**map):
     header = tmpl('header', encoding=self.encoding, **map)
     if 'mimetype' not in tmpl:
         # old template with inline HTTP headers
         header_file = cStringIO.StringIO(templater.stringify(header))
         msg = mimetools.Message(header_file, 0)
         header = header_file.read()
     yield header
示例#6
0
    def run_wsgi(self, req):
        try:
            try:
                #log.debug("Inside HgRedmine::run_wsgi : " + str(req.env))


                db = connect(self.dsn)

                self.refresh()
                self.findrepos(db)

                virtual = req.env.get("PATH_INFO", "").strip('/')

                tmpl = self.templater(req)
                ctype = tmpl('mimetype', encoding=encoding.encoding)
                ctype = templater.stringify(ctype)

                # a static file
                if virtual.startswith('static/') or 'static' in req.form:
                    if virtual.startswith('static/'):
                        fname = virtual[7:]
                    else:
                        fname = req.form['static'][0]
                    static = templater.templatepath('static')
                    return (staticfile(static, fname, req),)

                self._user_login(db, req)
                # top-level index
                #if not virtual:
                    ## only administrators can list repositories
                    #if self._is_admin(req):
                        #req.respond(HTTP_OK, ctype)
                        #return self.makeindex(req, tmpl)
                    #else:
                        #self._send_challenge(req)

                # navigate to hgweb
                project_id = virtual.split('/')[0]

                repos = dict(self.repos)

                real = repos.get(project_id)

                if real:
                    req.env['REPO_NAME'] = project_id

                    try:
                        repo = hg.repository(self.ui.copy(), str(real))
                        self._setup_repo(db, repo, project_id)
                        #log.debug("Calling HgWebRedmine with " + str(self.realm) + str(repo))
                        return HgwebRedmine(db, self.realm, repo).run_wsgi(req)
                    except IOError, inst:
                        msg = inst.strerror
                        raise ErrorResponse(HTTP_SERVER_ERROR, msg)
                    except error.RepoError, inst:
                        raise ErrorResponse(HTTP_SERVER_ERROR, str(inst))
示例#7
0
文件: color.py 项目: guitao/hg-stable
def templatelabel(context, mapping, args):
    if len(args) != 2:
        # i18n: "label" is a keyword
        raise error.ParseError(_("label expects two arguments"))

    thing = templater.stringify(args[1][0](context, mapping, args[1][1]))
    thing = templater.runtemplate(context, mapping, templater.compiletemplate(thing, context))

    # apparently, repo could be a string that is the favicon?
    repo = mapping.get("repo", "")
    if isinstance(repo, str):
        return thing

    label = templater.stringify(args[0][0](context, mapping, args[0][1]))
    label = templater.runtemplate(context, mapping, templater.compiletemplate(label, context))

    thing = templater.stringify(thing)
    label = templater.stringify(label)

    return repo.ui.label(thing, label)
示例#8
0
def templatelabel(context, mapping, args):
    if len(args) != 2:
        # i18n: "label" is a keyword
        raise error.ParseError(_("label expects two arguments"))

    # add known effects to the mapping so symbols like 'red', 'bold',
    # etc. don't need to be quoted
    mapping.update(dict([(k, k) for k in _effects]))

    thing = templater._evalifliteral(args[1], context, mapping)

    # apparently, repo could be a string that is the favicon?
    repo = mapping.get('repo', '')
    if isinstance(repo, str):
        return thing

    label = templater._evalifliteral(args[0], context, mapping)

    thing = templater.stringify(thing)
    label = templater.stringify(label)

    return repo.ui.label(thing, label)
示例#9
0
def templatelabel(context, mapping, args):
    if len(args) != 2:
        # i18n: "label" is a keyword
        raise error.ParseError(_("label expects two arguments"))

    # add known effects to the mapping so symbols like 'red', 'bold',
    # etc. don't need to be quoted
    mapping.update(dict([(k, k) for k in _effects]))

    thing = args[1][0](context, mapping, args[1][1])

    # apparently, repo could be a string that is the favicon?
    repo = mapping.get('repo', '')
    if isinstance(repo, str):
        return thing

    label = args[0][0](context, mapping, args[0][1])

    thing = templater.stringify(thing)
    label = templater.stringify(label)

    return repo.ui.label(thing, label)
示例#10
0
文件: color.py 项目: ddollar/gobuild
def templatelabel(context, mapping, args):
    if len(args) != 2:
        # i18n: "label" is a keyword
        raise error.ParseError(_("label expects two arguments"))

    thing = templater.stringify(args[1][0](context, mapping, args[1][1]))
    thing = templater.runtemplate(context, mapping,
                                  templater.compiletemplate(thing, context))

    # apparently, repo could be a string that is the favicon?
    repo = mapping.get('repo', '')
    if isinstance(repo, str):
        return thing

    label = templater.stringify(args[0][0](context, mapping, args[0][1]))
    label = templater.runtemplate(context, mapping,
                                  templater.compiletemplate(label, context))

    thing = templater.stringify(thing)
    label = templater.stringify(label)

    return repo.ui.label(thing, label)
示例#11
0
    def run_wsgi(self, req):
        try:
            try:
                self.refresh()

                virtual = req.env.get("PATH_INFO", "").strip('/')
                tmpl = self.templater(req)
                ctype = tmpl('mimetype', encoding=encoding.encoding)
                ctype = templater.stringify(ctype)

                # a static file
                if virtual.startswith('static/') or 'static' in req.form:
                    if virtual.startswith('static/'):
                        fname = virtual[7:]
                    else:
                        fname = req.form['static'][0]
                    static = self.ui.config("web",
                                            "static",
                                            None,
                                            untrusted=False)
                    if not static:
                        tp = self.templatepath or templater.templatepaths()
                        if isinstance(tp, str):
                            tp = [tp]
                        static = [os.path.join(p, 'static') for p in tp]
                    staticfile(static, fname, req)
                    return []

                # top-level index
                elif not virtual:
                    req.respond(HTTP_OK, ctype)
                    return self.makeindex(req, tmpl)

                # nested indexes and hgwebs

                repos = dict(self.repos)
                virtualrepo = virtual
                while virtualrepo:
                    real = repos.get(virtualrepo)
                    if real:
                        req.env['REPO_NAME'] = virtualrepo
                        try:
                            # ensure caller gets private copy of ui
                            repo = hg.repository(self.ui.copy(), real)
                            return hgweb(repo).run_wsgi(req)
                        except IOError, inst:
                            msg = inst.strerror
                            raise ErrorResponse(HTTP_SERVER_ERROR, msg)
                        except error.RepoError, inst:
                            raise ErrorResponse(HTTP_SERVER_ERROR, str(inst))
示例#12
0
    def run_wsgi(self, req):
        try:
            try:
                self.refresh()

                virtual = req.env.get("PATH_INFO", "").strip('/')
                tmpl = self.templater(req)
                ctype = tmpl('mimetype', encoding=encoding.encoding)
                ctype = templater.stringify(ctype)

                # a static file
                if virtual.startswith('static/') or 'static' in req.form:
                    if virtual.startswith('static/'):
                        fname = virtual[7:]
                    else:
                        fname = req.form['static'][0]
                    static = self.ui.config("web", "static", None,
                                            untrusted=False)
                    if not static:
                        tp = self.templatepath or templater.templatepaths()
                        if isinstance(tp, str):
                            tp = [tp]
                        static = [os.path.join(p, 'static') for p in tp]
                    staticfile(static, fname, req)
                    return []

                # top-level index
                elif not virtual:
                    req.respond(HTTP_OK, ctype)
                    return self.makeindex(req, tmpl)

                # nested indexes and hgwebs

                repos = dict(self.repos)
                virtualrepo = virtual
                while virtualrepo:
                    real = repos.get(virtualrepo)
                    if real:
                        req.env['REPO_NAME'] = virtualrepo
                        try:
                            # ensure caller gets private copy of ui
                            repo = hg.repository(self.ui.copy(), real)
                            return hgweb(repo).run_wsgi(req)
                        except IOError, inst:
                            msg = inst.strerror
                            raise ErrorResponse(HTTP_SERVER_ERROR, msg)
                        except error.RepoError, inst:
                            raise ErrorResponse(HTTP_SERVER_ERROR, str(inst))
示例#13
0
文件: hgwide.py 项目: gkleiman/wide
    def run_wsgi(self, req):
        try:
            try:
                db, self.placeholder = connect(self.dsn)

                self.refresh()
                self.findrepos(db)

                virtual = req.env.get("PATH_INFO", "").strip('/')
                tmpl = self.templater(req)
                ctype = tmpl('mimetype', encoding=encoding.encoding)
                ctype = templater.stringify(ctype)

                # a static file
                if virtual.startswith('static/') or 'static' in req.form:
                    if virtual.startswith('static/'):
                        fname = virtual[7:]
                    else:
                        fname = req.form['static'][0]
                    static = templater.templatepath('static')
                    return (staticfile(static, fname, req),)

                self._user_login(db, req)

                # top-level index
                if not virtual:
                    # nobody can list repositories
                    self._send_challenge(req)

                # navigate to hgweb
                repository_path = '/'.join(virtual.split('/')[0:2])

                repos = dict(self.repos)
                real = repos.get(repository_path)

                if real:
                    req.env['REPO_NAME'] = repository_path
                    req.env['PROJECT_ID'], req.env['PROJECT_OWNER_ID'] = self._project_info_from_repo_path(db, repository_path)

                    try:
                        repo = hg.repository(self.ui, real)
                        self._setup_repo(db, repo, repository_path)
                        return HgwebWide(db, self.placeholder, self.realm, repo).run_wsgi(req)
                    except IOError, inst:
                        msg = inst.strerror
                        raise ErrorResponse(HTTP_SERVER_ERROR, msg)
                    except error.RepoError, inst:
                        raise ErrorResponse(HTTP_SERVER_ERROR, str(inst))
示例#14
0
def hgwebinit_run_wsgi_wrapper(orig, obj, req):
    """Handles hgwebdir_mod requests, looking for pushes to non-existent repos.
    If one is detected, the user is first authorized and then prompted to init.
    Following that we simply hand the request off ot the next handler in the
    chain - typically hgwebdir_mod itself."""
    try:
        tmpl = obj.templater(req)
        ctype = tmpl("mimetype", encoding=encoding.encoding)
        ctype = templater.stringify(ctype)

        obj.refresh()

        # Do our stuff...
        if should_create_repo(obj, req):
            # Ah, but is this user allowed to create repos?
            if create_allowed(obj.ui, req):
                virtual = req.env.get("PATH_INFO", "").strip("/")

                paths = {}
                for name, value in obj.ui.configitems("paths"):
                    paths[name] = value

                local = local_path_for_repo(virtual, paths)

                if obj.ui.configbool("web", "implicit_init", False):
                    # Go ahead and init if implicit creation is enabled
                    hg.repository(obj.ui, path=local, create=True)
                else:
                    # Find out what the client wants.
                    # Only the capabilities and init commands are supported.
                    cmd = req.form.get("cmd", [""])[0]
                    if protocol.iscmd(cmd) and cmd in ("capabilities", "init"):
                        repo = emptyrepo(baseui=obj.ui)
                        return protocol.call(repo, req, cmd)

                # force refresh
                obj.lastrefresh = 0

    except ErrorResponse, err:
        req.respond(err, ctype)
        return tmpl("error", error=err.message or "")
示例#15
0
    def run_wsgi(self, req):
        try:
            try:
                self.refresh()

                virtual = req.env.get("PATH_INFO", "").strip('/')
                tmpl = self.templater(req)
                ctype = tmpl('mimetype', encoding=encoding.encoding)
                ctype = templater.stringify(ctype)

                # a static file
                if virtual.startswith('static/') or 'static' in req.form:
                    if virtual.startswith('static/'):
                        fname = virtual[7:]
                    else:
                        fname = req.form['static'][0]
                    static = templater.templatepath('static')
                    return (staticfile(static, fname, req),)

                # top-level index
                elif not virtual:
                    req.respond(HTTP_OK, ctype)
                    return self.makeindex(req, tmpl)

                # nested indexes and hgwebs

                repos = dict(self.repos)
                virtualrepo = virtual
                while virtualrepo:
                    real = repos.get(virtualrepo)
                    if real:
                        req.env['REPO_NAME'] = virtualrepo
                        try:
                            repo = hg.repository(self.ui, real)
                            return hgweb(repo).run_wsgi(req)
                        except IOError, inst:
                            msg = inst.strerror
                            raise ErrorResponse(HTTP_SERVER_ERROR, msg)
                        except error.RepoError, inst:
                            raise ErrorResponse(HTTP_SERVER_ERROR, str(inst))
示例#16
0
    def run_wsgi(self, req):
        try:
            try:
                self.refresh()

                virtual = req.env.get("PATH_INFO", "").strip('/')
                tmpl = self.templater(req)
                ctype = tmpl('mimetype', encoding=encoding.encoding)
                ctype = templater.stringify(ctype)

                # a static file
                if virtual.startswith('static/') or 'static' in req.form:
                    if virtual.startswith('static/'):
                        fname = virtual[7:]
                    else:
                        fname = req.form['static'][0]
                    static = templater.templatepath('static')
                    return (staticfile(static, fname, req), )

                # top-level index
                elif not virtual:
                    req.respond(HTTP_OK, ctype)
                    return self.makeindex(req, tmpl)

                # nested indexes and hgwebs

                repos = dict(self.repos)
                virtualrepo = virtual
                while virtualrepo:
                    real = repos.get(virtualrepo)
                    if real:
                        req.env['REPO_NAME'] = virtualrepo
                        try:
                            repo = hg.repository(self.ui, real)
                            return hgweb(repo).run_wsgi(req)
                        except IOError, inst:
                            msg = inst.strerror
                            raise ErrorResponse(HTTP_SERVER_ERROR, msg)
                        except error.RepoError, inst:
                            raise ErrorResponse(HTTP_SERVER_ERROR, str(inst))
示例#17
0
class hgweb(object):
    def __init__(self, repo, name=None, baseui=None):
        if isinstance(repo, str):
            if baseui:
                u = baseui.copy()
            else:
                u = ui.ui()
            r = hg.repository(u, repo)
        else:
            # we trust caller to give us a private copy
            r = repo

        r = self._getview(r)
        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')
        self.repo = r
        hook.redirect(True)
        self.repostate = ((-1, -1), (-1, -1))
        self.mtime = -1
        self.reponame = name
        self.archives = 'zip', 'gz', 'bz2'
        self.stripecount = 1
        # a repo owner may set web.templates in .hg/hgrc to get any file
        # readable by the user running the CGI script
        self.templatepath = self.config('web', 'templates')
        self.websubtable = self.loadwebsub()

    # The CGI scripts are often run by a user different from the repo owner.
    # Trust the settings from the .hg/hgrc files by default.
    def config(self, section, name, default=None, untrusted=True):
        return self.repo.ui.config(section, name, default, untrusted=untrusted)

    def configbool(self, section, name, default=False, untrusted=True):
        return self.repo.ui.configbool(section,
                                       name,
                                       default,
                                       untrusted=untrusted)

    def configlist(self, section, name, default=None, untrusted=True):
        return self.repo.ui.configlist(section,
                                       name,
                                       default,
                                       untrusted=untrusted)

    def _getview(self, repo):
        viewconfig = repo.ui.config('web', 'view', 'served', untrusted=True)
        if viewconfig == 'all':
            return repo.unfiltered()
        elif viewconfig in repoview.filtertable:
            return repo.filtered(viewconfig)
        else:
            return repo.filtered('served')

    def refresh(self, request=None):
        st = get_stat(self.repo.spath)
        pst = get_stat(self.repo.spath, 'phaseroots')
        # changelog mtime and size, phaseroots mtime and size
        repostate = ((st.st_mtime, st.st_size), (pst.st_mtime, pst.st_size))
        # we need to compare file size in addition to mtime to catch
        # changes made less than a second ago
        if repostate != self.repostate:
            r = hg.repository(self.repo.baseui, self.repo.url())
            self.repo = self._getview(r)
            self.maxchanges = int(self.config("web", "maxchanges", 10))
            self.stripecount = int(self.config("web", "stripes", 1))
            self.maxshortchanges = int(
                self.config("web", "maxshortchanges", 60))
            self.maxfiles = int(self.config("web", "maxfiles", 10))
            self.allowpull = self.configbool("web", "allowpull", True)
            encoding.encoding = self.config("web", "encoding",
                                            encoding.encoding)
            # update these last to avoid threads seeing empty settings
            self.repostate = repostate
            # mtime is needed for ETag
            self.mtime = st.st_mtime
        if request:
            self.repo.ui.environ = request.env

    def run(self):
        if not os.environ.get('GATEWAY_INTERFACE', '').startswith("CGI/1."):
            raise RuntimeError("This function is only intended to be "
                               "called while running as a CGI script.")
        import mercurial.hgweb.wsgicgi as wsgicgi
        wsgicgi.launch(self)

    def __call__(self, env, respond):
        req = wsgirequest(env, respond)
        return self.run_wsgi(req)

    def run_wsgi(self, req):

        self.refresh(req)

        # work with CGI variables to create coherent structure
        # use SCRIPT_NAME, PATH_INFO and QUERY_STRING as well as our REPO_NAME

        req.url = req.env['SCRIPT_NAME']
        if not req.url.endswith('/'):
            req.url += '/'
        if 'REPO_NAME' in req.env:
            req.url += req.env['REPO_NAME'] + '/'

        if 'PATH_INFO' in req.env:
            parts = req.env['PATH_INFO'].strip('/').split('/')
            repo_parts = req.env.get('REPO_NAME', '').split('/')
            if parts[:len(repo_parts)] == repo_parts:
                parts = parts[len(repo_parts):]
            query = '/'.join(parts)
        else:
            query = req.env['QUERY_STRING'].split('&', 1)[0]
            query = query.split(';', 1)[0]

        # process this if it's a protocol request
        # protocol bits don't need to create any URLs
        # and the clients always use the old URL structure

        cmd = req.form.get('cmd', [''])[0]
        if protocol.iscmd(cmd):
            try:
                if query:
                    raise ErrorResponse(HTTP_NOT_FOUND)
                if cmd in perms:
                    self.check_perm(req, perms[cmd])
                return protocol.call(self.repo, req, cmd)
            except ErrorResponse, inst:
                # A client that sends unbundle without 100-continue will
                # break if we respond early.
                if (cmd == 'unbundle' and
                    (req.env.get('HTTP_EXPECT', '').lower() != '100-continue')
                        or req.env.get('X-HgHttp2', '')):
                    req.drain()
                else:
                    req.headers.append(('Connection', 'Close'))
                req.respond(inst,
                            protocol.HGTYPE,
                            body='0\n%s\n' % inst.message)
                return ''

        # translate user-visible url structure to internal structure

        args = query.split('/', 2)
        if 'cmd' not in req.form and args and args[0]:

            cmd = args.pop(0)
            style = cmd.rfind('-')
            if style != -1:
                req.form['style'] = [cmd[:style]]
                cmd = cmd[style + 1:]

            # avoid accepting e.g. style parameter as command
            if util.safehasattr(webcommands, cmd):
                req.form['cmd'] = [cmd]

            if cmd == 'static':
                req.form['file'] = ['/'.join(args)]
            else:
                if args and args[0]:
                    node = args.pop(0)
                    req.form['node'] = [node]
                if args:
                    req.form['file'] = args

            ua = req.env.get('HTTP_USER_AGENT', '')
            if cmd == 'rev' and 'mercurial' in ua:
                req.form['style'] = ['raw']

            if cmd == 'archive':
                fn = req.form['node'][0]
                for type_, spec in self.archive_specs.iteritems():
                    ext = spec[2]
                    if fn.endswith(ext):
                        req.form['node'] = [fn[:-len(ext)]]
                        req.form['type'] = [type_]

        # process the web interface request

        try:
            tmpl = self.templater(req)
            ctype = tmpl('mimetype', encoding=encoding.encoding)
            ctype = templater.stringify(ctype)

            # check read permissions non-static content
            if cmd != 'static':
                self.check_perm(req, None)

            if cmd == '':
                req.form['cmd'] = [tmpl.cache['default']]
                cmd = req.form['cmd'][0]

            if self.configbool('web', 'cache', True):
                caching(self, req)  # sets ETag header or raises NOT_MODIFIED
            if cmd not in webcommands.__all__:
                msg = 'no such method: %s' % cmd
                raise ErrorResponse(HTTP_BAD_REQUEST, msg)
            elif cmd == 'file' and 'raw' in req.form.get('style', []):
                self.ctype = ctype
                content = webcommands.rawfile(self, req, tmpl)
            else:
                content = getattr(webcommands, cmd)(self, req, tmpl)
                req.respond(HTTP_OK, ctype)

            return content

        except (error.LookupError, error.RepoLookupError), err:
            req.respond(HTTP_NOT_FOUND, ctype)
            msg = str(err)
            if (util.safehasattr(err, 'name')
                    and not isinstance(err, error.ManifestLookupError)):
                msg = 'revision not found: %s' % err.name
            return tmpl('error', error=msg)
示例#18
0
                    req.form['file'] = args

            if cmd == 'archive':
                fn = req.form['node'][0]
                for type_, spec in self.archive_specs.iteritems():
                    ext = spec[2]
                    if fn.endswith(ext):
                        req.form['node'] = [fn[:-len(ext)]]
                        req.form['type'] = [type_]

        # process the web interface request

        try:
            tmpl = self.templater(req)
            ctype = tmpl('mimetype', encoding=self.encoding)
            ctype = templater.stringify(ctype)

            # check read permissions non-static content
            if cmd != 'static':
                self.check_perm(req, None)

            if cmd == '':
                req.form['cmd'] = [tmpl.cache['default']]
                cmd = req.form['cmd'][0]

            if cmd not in webcommands.__all__:
                msg = 'no such method: %s' % cmd
                raise ErrorResponse(HTTP_BAD_REQUEST, msg)
            elif cmd == 'file' and 'raw' in req.form.get('style', []):
                self.ctype = ctype
                content = webcommands.rawfile(self, req, tmpl)
示例#19
0
                req.form['style'] = ['raw']

            if cmd == 'archive':
                fn = req.form['node'][0]
                for type_, spec in self.archive_specs.iteritems():
                    ext = spec[2]
                    if fn.endswith(ext):
                        req.form['node'] = [fn[:-len(ext)]]
                        req.form['type'] = [type_]

        # process the web interface request

        try:
            tmpl = self.templater(req)
            ctype = tmpl('mimetype', encoding=encoding.encoding)
            ctype = templater.stringify(ctype)

            # check read permissions non-static content
            if cmd != 'static':
                self.check_perm(req, None)

            if cmd == '':
                req.form['cmd'] = [tmpl.cache['default']]
                cmd = req.form['cmd'][0]

            if cmd not in webcommands.__all__:
                msg = 'no such method: %s' % cmd
                raise ErrorResponse(HTTP_BAD_REQUEST, msg)
            elif cmd == 'file' and 'raw' in req.form.get('style', []):
                self.ctype = ctype
                content = webcommands.rawfile(self, req, tmpl)
示例#20
0
    def _runwsgi(self, req, repo):
        rctx = requestcontext(self, repo)

        # This state is global across all threads.
        encoding.encoding = rctx.config('web', 'encoding', encoding.encoding)
        rctx.repo.ui.environ = req.env

        # work with CGI variables to create coherent structure
        # use SCRIPT_NAME, PATH_INFO and QUERY_STRING as well as our REPO_NAME

        req.url = req.env['SCRIPT_NAME']
        if not req.url.endswith('/'):
            req.url += '/'
        if 'REPO_NAME' in req.env:
            req.url += req.env['REPO_NAME'] + '/'

        if 'PATH_INFO' in req.env:
            parts = req.env['PATH_INFO'].strip('/').split('/')
            repo_parts = req.env.get('REPO_NAME', '').split('/')
            if parts[:len(repo_parts)] == repo_parts:
                parts = parts[len(repo_parts):]
            query = '/'.join(parts)
        else:
            query = req.env['QUERY_STRING'].split('&', 1)[0]
            query = query.split(';', 1)[0]

        # process this if it's a protocol request
        # protocol bits don't need to create any URLs
        # and the clients always use the old URL structure

        cmd = req.form.get('cmd', [''])[0]
        if protocol.iscmd(cmd):
            try:
                if query:
                    raise ErrorResponse(HTTP_NOT_FOUND)
                if cmd in perms:
                    self.check_perm(rctx, req, perms[cmd])
                return protocol.call(rctx.repo, req, cmd)
            except ErrorResponse as inst:
                # A client that sends unbundle without 100-continue will
                # break if we respond early.
                if (cmd == 'unbundle' and
                    (req.env.get('HTTP_EXPECT',
                                 '').lower() != '100-continue') or
                    req.env.get('X-HgHttp2', '')):
                    req.drain()
                else:
                    req.headers.append(('Connection', 'Close'))
                req.respond(inst, protocol.HGTYPE,
                            body='0\n%s\n' % inst)
                return ''

        # translate user-visible url structure to internal structure

        args = query.split('/', 2)
        if 'cmd' not in req.form and args and args[0]:

            cmd = args.pop(0)
            style = cmd.rfind('-')
            if style != -1:
                req.form['style'] = [cmd[:style]]
                cmd = cmd[style + 1:]

            # avoid accepting e.g. style parameter as command
            if util.safehasattr(webcommands, cmd):
                req.form['cmd'] = [cmd]

            if cmd == 'static':
                req.form['file'] = ['/'.join(args)]
            else:
                if args and args[0]:
                    node = args.pop(0).replace('%2F', '/')
                    req.form['node'] = [node]
                if args:
                    req.form['file'] = args

            ua = req.env.get('HTTP_USER_AGENT', '')
            if cmd == 'rev' and 'mercurial' in ua:
                req.form['style'] = ['raw']

            if cmd == 'archive':
                fn = req.form['node'][0]
                for type_, spec in rctx.archivespecs.iteritems():
                    ext = spec[2]
                    if fn.endswith(ext):
                        req.form['node'] = [fn[:-len(ext)]]
                        req.form['type'] = [type_]

        # process the web interface request

        try:
            tmpl = rctx.templater(req)
            ctype = tmpl('mimetype', encoding=encoding.encoding)
            ctype = templater.stringify(ctype)

            # check read permissions non-static content
            if cmd != 'static':
                self.check_perm(rctx, req, None)

            if cmd == '':
                req.form['cmd'] = [tmpl.cache['default']]
                cmd = req.form['cmd'][0]

            if rctx.configbool('web', 'cache', True):
                caching(self, req) # sets ETag header or raises NOT_MODIFIED
            if cmd not in webcommands.__all__:
                msg = 'no such method: %s' % cmd
                raise ErrorResponse(HTTP_BAD_REQUEST, msg)
            elif cmd == 'file' and 'raw' in req.form.get('style', []):
                rctx.ctype = ctype
                content = webcommands.rawfile(rctx, req, tmpl)
            else:
                content = getattr(webcommands, cmd)(rctx, req, tmpl)
                req.respond(HTTP_OK, ctype)

            return content

        except (error.LookupError, error.RepoLookupError) as err:
            req.respond(HTTP_NOT_FOUND, ctype)
            msg = str(err)
            if (util.safehasattr(err, 'name') and
                not isinstance(err,  error.ManifestLookupError)):
                msg = 'revision not found: %s' % err.name
            return tmpl('error', error=msg)
        except (error.RepoError, error.RevlogError) as inst:
            req.respond(HTTP_SERVER_ERROR, ctype)
            return tmpl('error', error=str(inst))
        except ErrorResponse as inst:
            req.respond(inst, ctype)
            if inst.code == HTTP_NOT_MODIFIED:
                # Not allowed to return a body on a 304
                return ['']
            return tmpl('error', error=str(inst))
示例#21
0
    def flush_buffer():
        if not file_buffer:
            return

        file_buffer.sort(cmp=cmp_buf)

        do_long = not should_format or long_format
        if not do_long:
            w = ui.termwidth()
            ml = max([len(n) for n,sp,sr,f,li in file_buffer])
            if flags:
                ml += 1
            ml = (((ml + 1) + 7) & ~7) - 1
            if ml > w / 2 - 2:
                do_long = True
                
        if do_long:
            outbuf = []
            for name, subpath, subrepo, fctx, linkinfo in file_buffer:
                kind = file_kind(fctx, subpath, linkinfo)
                
                if formatter:
                    mode = 0o100644
                    
                    if linkinfo:
                        mode = 0o120755
                    else:
                        if not fctx:
                            mode = 0o040755
                        else:
                            ctxflags = fctx.flags()
                            if 'l' in ctxflags:
                                mode = 0o120755
                            if 'x' in ctxflags:
                                mode = mode | 0o0111

                    if linkinfo:
                        subrepourl = linkinfo[0]
                        subreporev = linkinfo[1]
                        subrepotype = linkinfo[2]
                    else:
                        subrepourl = ''
                        subreporev = ''
                        subrepotype = ''
                    
                    if not fctx:
                        user = '******'
                        date = (0, 0)
                        size = 0
                        rev = -1
                        node = 'f'*40
                        desc = ''
                        branch = ''
                    else:
                        size = fctx.size()
                        rev = fctx.linkrev()
                        cctx = subrepo[rev]
                        user = cctx.user()
                        date = cctx.date()
                        node = cctx.hex()
                        desc = cctx.description()
                        branch = cctx.branch()

                    info = { 'name': name,
                             'kind': kind,
                             'mode': mode,
                             'author': user,
                             'date': date,
                             'size': size,
                             'rev': rev,
                             'node': node,
                             'subrepo': subpath,
                             'desc': desc,
                             'branch': branch,
                             'linkurl': subrepourl,
                             'linkrev': subreporev,
                             'linktype': subrepotype }

                    try:
                        fmt = templater.stringify(formatter(template_name,
                                                            **info))
                    except error.ParseError, e:
                        raise util.Abort('bad template - at character %s: %s'
                                         % (e.args[1], e.args[0]))
                    
                    if align_columns:
                        outbuf.append(fmt.split('\0'))
                    else:
                        ui.write(fmt)
                else:
                    ui.write('%s%s\n' % (name, kind))

            del file_buffer[:]

            if align_columns and outbuf:
                colwidths = [len(n) for n in outbuf[0]]
                for line in outbuf:
                    colwidths = [max(colwidths[n], len(line[n]))
                                 for n in xrange(0, len(colwidths))]

                fmtstr = []
                for ncol in xrange(0, len(colwidths)):
                    if ncol >= len(align_columns):
                        alignment = 'l'
                    else:
                        alignment = align_columns[ncol]
                    width = colwidths[ncol]
                    
                    if alignment == 'l':
                        # Trailing 'l' columns are not padded
                        if ncol == len(colwidths) - 1:
                            fmtstr.append('{{{0}}}'.format(ncol))
                        else:
                            fmtstr.append('{{{0}:<{1}}}'.format(ncol, width))
                    elif alignment == 'c':
                        fmtstr.append('{{{0}:^{1}}}'.format(ncol, width))
                    else:
                        fmtstr.append('{{{0}:>{1}}}'.format(ncol, width))

                fmtstr = ' '.join(fmtstr) + '\n'
                
                for line in outbuf:
                    ui.write(fmtstr.format(*line))
                    
            return
示例#22
0
    def run_wsgi(self, req):
        try:
            self.refresh()

            virtual = req.env.get("PATH_INFO", "").strip('/')
            tmpl = self.templater(req)
            ctype = tmpl('mimetype', encoding=encoding.encoding)
            ctype = templater.stringify(ctype)

            # a static file
            if virtual.startswith('static/') or 'static' in req.form:
                if virtual.startswith('static/'):
                    fname = virtual[7:]
                else:
                    fname = req.form['static'][0]
                static = self.ui.config("web", "static", None,
                                        untrusted=False)
                if not static:
                    tp = self.templatepath or templater.templatepaths()
                    if isinstance(tp, str):
                        tp = [tp]
                    static = [os.path.join(p, 'static') for p in tp]
                staticfile(static, fname, req)
                return []

            # top-level index
            elif not virtual:
                req.respond(HTTP_OK, ctype)
                return self.makeindex(req, tmpl)

            # nested indexes and hgwebs

            repos = dict(self.repos)
            virtualrepo = virtual
            while virtualrepo:
                real = repos.get(virtualrepo)
                if real:
                    req.env['REPO_NAME'] = virtualrepo
                    try:
                        # ensure caller gets private copy of ui
                        repo = hg.repository(self.ui.copy(), real)
                        return hgweb(repo).run_wsgi(req)
                    except IOError as inst:
                        msg = inst.strerror
                        raise ErrorResponse(HTTP_SERVER_ERROR, msg)
                    except error.RepoError as inst:
                        raise ErrorResponse(HTTP_SERVER_ERROR, str(inst))

                up = virtualrepo.rfind('/')
                if up < 0:
                    break
                virtualrepo = virtualrepo[:up]

            # browse subdirectories
            subdir = virtual + '/'
            if [r for r in repos if r.startswith(subdir)]:
                req.respond(HTTP_OK, ctype)
                return self.makeindex(req, tmpl, subdir)

            # prefixes not found
            req.respond(HTTP_NOT_FOUND, ctype)
            return tmpl("notfound", repo=virtual)

        except ErrorResponse as err:
            req.respond(err, ctype)
            return tmpl('error', error=err.message or '')
        finally:
            tmpl = None
示例#23
0
    def run_wsgi(self, req):

        self.refresh()

        # expand form shortcuts

        for k in shortcuts.iterkeys():
            if k in req.form:
                for name, value in shortcuts[k]:
                    if value is None:
                        value = req.form[k]
                    req.form[name] = value
                del req.form[k]

        # work with CGI variables to create coherent structure
        # use SCRIPT_NAME, PATH_INFO and QUERY_STRING as well as our REPO_NAME

        req.url = req.env['SCRIPT_NAME']
        if not req.url.endswith('/'):
            req.url += '/'
        if 'REPO_NAME' in req.env:
            req.url += req.env['REPO_NAME'] + '/'

        if 'PATH_INFO' in req.env:
            parts = req.env['PATH_INFO'].strip('/').split('/')
            repo_parts = req.env.get('REPO_NAME', '').split('/')
            if parts[:len(repo_parts)] == repo_parts:
                parts = parts[len(repo_parts):]
            query = '/'.join(parts)
        else:
            query = req.env['QUERY_STRING'].split('&', 1)[0]
            query = query.split(';', 1)[0]

        # translate user-visible url structure to internal structure

        args = query.split('/', 2)
        if 'cmd' not in req.form and args and args[0]:

            cmd = args.pop(0)
            style = cmd.rfind('-')
            if style != -1:
                req.form['style'] = [cmd[:style]]
                cmd = cmd[style+1:]

            # avoid accepting e.g. style parameter as command
            if hasattr(webcommands, cmd) or hasattr(protocol, cmd):
                req.form['cmd'] = [cmd]

            if args and args[0]:
                node = args.pop(0)
                req.form['node'] = [node]
            if args:
                req.form['file'] = args

            if cmd == 'static':
                req.form['file'] = req.form['node']
            elif cmd == 'archive':
                fn = req.form['node'][0]
                for type_, spec in self.archive_specs.iteritems():
                    ext = spec[2]
                    if fn.endswith(ext):
                        req.form['node'] = [fn[:-len(ext)]]
                        req.form['type'] = [type_]

        # process this if it's a protocol request

        cmd = req.form.get('cmd', [''])[0]
        if cmd in protocol.__all__:
            method = getattr(protocol, cmd)
            method(self, req)
            return

        # process the web interface request

        try:

            tmpl = self.templater(req)
            try:
                ctype = tmpl('mimetype', encoding=self.encoding)
                ctype = templater.stringify(ctype)
            except KeyError:
                # old templates with inline HTTP headers?
                if 'mimetype' in tmpl:
                    raise
                header = tmpl('header', encoding=self.encoding)
                header_file = cStringIO.StringIO(templater.stringify(header))
                msg = mimetools.Message(header_file, 0)
                ctype = msg['content-type']

            if cmd == '':
                req.form['cmd'] = [tmpl.cache['default']]
                cmd = req.form['cmd'][0]

            if cmd not in webcommands.__all__:
                msg = 'no such method: %s' % cmd
                raise ErrorResponse(HTTP_BAD_REQUEST, msg)
            elif cmd == 'file' and 'raw' in req.form.get('style', []):
                self.ctype = ctype
                content = webcommands.rawfile(self, req, tmpl)
            else:
                content = getattr(webcommands, cmd)(self, req, tmpl)
                req.respond(HTTP_OK, ctype)

            req.write(content)
            del tmpl

        except revlog.LookupError, err:
            req.respond(HTTP_NOT_FOUND, ctype)
            msg = str(err)
            if 'manifest' not in msg:
                msg = 'revision not found: %s' % err.name
            req.write(tmpl('error', error=msg))
示例#24
0
class hgweb(object):
    def __init__(self, repo, name=None, baseui=None):
        if isinstance(repo, str):
            if baseui:
                u = baseui.copy()
            else:
                u = ui.ui()
            self.repo = hg.repository(u, repo)
        else:
            self.repo = repo

        self.repo.ui.setconfig('ui', 'report_untrusted', 'off')
        self.repo.ui.setconfig('ui', 'interactive', 'off')
        hook.redirect(True)
        self.mtime = -1
        self.reponame = name
        self.archives = 'zip', 'gz', 'bz2'
        self.stripecount = 1
        # a repo owner may set web.templates in .hg/hgrc to get any file
        # readable by the user running the CGI script
        self.templatepath = self.config('web', 'templates')

    # The CGI scripts are often run by a user different from the repo owner.
    # Trust the settings from the .hg/hgrc files by default.
    def config(self, section, name, default=None, untrusted=True):
        return self.repo.ui.config(section, name, default, untrusted=untrusted)

    def configbool(self, section, name, default=False, untrusted=True):
        return self.repo.ui.configbool(section,
                                       name,
                                       default,
                                       untrusted=untrusted)

    def configlist(self, section, name, default=None, untrusted=True):
        return self.repo.ui.configlist(section,
                                       name,
                                       default,
                                       untrusted=untrusted)

    def refresh(self, request=None):
        if request:
            self.repo.ui.environ = request.env
        mtime = get_mtime(self.repo.spath)
        if mtime != self.mtime:
            self.mtime = mtime
            self.repo = hg.repository(self.repo.ui, self.repo.root)
            self.maxchanges = int(self.config("web", "maxchanges", 10))
            self.stripecount = int(self.config("web", "stripes", 1))
            self.maxshortchanges = int(
                self.config("web", "maxshortchanges", 60))
            self.maxfiles = int(self.config("web", "maxfiles", 10))
            self.allowpull = self.configbool("web", "allowpull", True)
            encoding.encoding = self.config("web", "encoding",
                                            encoding.encoding)

    def run(self):
        if not os.environ.get('GATEWAY_INTERFACE', '').startswith("CGI/1."):
            raise RuntimeError("This function is only intended to be "
                               "called while running as a CGI script.")
        import mercurial.hgweb.wsgicgi as wsgicgi
        wsgicgi.launch(self)

    def __call__(self, env, respond):
        req = wsgirequest(env, respond)
        return self.run_wsgi(req)

    def run_wsgi(self, req):

        self.refresh(req)

        # work with CGI variables to create coherent structure
        # use SCRIPT_NAME, PATH_INFO and QUERY_STRING as well as our REPO_NAME

        req.url = req.env['SCRIPT_NAME']
        if not req.url.endswith('/'):
            req.url += '/'
        if 'REPO_NAME' in req.env:
            req.url += req.env['REPO_NAME'] + '/'

        if 'PATH_INFO' in req.env:
            parts = req.env['PATH_INFO'].strip('/').split('/')
            repo_parts = req.env.get('REPO_NAME', '').split('/')
            if parts[:len(repo_parts)] == repo_parts:
                parts = parts[len(repo_parts):]
            query = '/'.join(parts)
        else:
            query = req.env['QUERY_STRING'].split('&', 1)[0]
            query = query.split(';', 1)[0]

        # process this if it's a protocol request
        # protocol bits don't need to create any URLs
        # and the clients always use the old URL structure

        cmd = req.form.get('cmd', [''])[0]
        if protocol.iscmd(cmd):
            try:
                if query:
                    raise ErrorResponse(HTTP_NOT_FOUND)
                if cmd in perms:
                    self.check_perm(req, perms[cmd])
                return protocol.call(self.repo, req, cmd)
            except ErrorResponse, inst:
                if cmd == 'unbundle':
                    req.drain()
                req.respond(inst, protocol.HGTYPE)
                return '0\n%s\n' % inst.message

        # translate user-visible url structure to internal structure

        args = query.split('/', 2)
        if 'cmd' not in req.form and args and args[0]:

            cmd = args.pop(0)
            style = cmd.rfind('-')
            if style != -1:
                req.form['style'] = [cmd[:style]]
                cmd = cmd[style + 1:]

            # avoid accepting e.g. style parameter as command
            if hasattr(webcommands, cmd):
                req.form['cmd'] = [cmd]
            else:
                cmd = ''

            if cmd == 'static':
                req.form['file'] = ['/'.join(args)]
            else:
                if args and args[0]:
                    node = args.pop(0)
                    req.form['node'] = [node]
                if args:
                    req.form['file'] = args

            ua = req.env.get('HTTP_USER_AGENT', '')
            if cmd == 'rev' and 'mercurial' in ua:
                req.form['style'] = ['raw']

            if cmd == 'archive':
                fn = req.form['node'][0]
                for type_, spec in self.archive_specs.iteritems():
                    ext = spec[2]
                    if fn.endswith(ext):
                        req.form['node'] = [fn[:-len(ext)]]
                        req.form['type'] = [type_]

        # process the web interface request

        try:
            tmpl = self.templater(req)
            ctype = tmpl('mimetype', encoding=encoding.encoding)
            ctype = templater.stringify(ctype)

            # check read permissions non-static content
            if cmd != 'static':
                self.check_perm(req, None)

            if cmd == '':
                req.form['cmd'] = [tmpl.cache['default']]
                cmd = req.form['cmd'][0]

            caching(self, req)  # sets ETag header or raises NOT_MODIFIED
            if cmd not in webcommands.__all__:
                msg = 'no such method: %s' % cmd
                raise ErrorResponse(HTTP_BAD_REQUEST, msg)
            elif cmd == 'file' and 'raw' in req.form.get('style', []):
                self.ctype = ctype
                content = webcommands.rawfile(self, req, tmpl)
            else:
                content = getattr(webcommands, cmd)(self, req, tmpl)
                req.respond(HTTP_OK, ctype)

            return content

        except error.LookupError, err:
            req.respond(HTTP_NOT_FOUND, ctype)
            msg = str(err)
            if 'manifest' not in msg:
                msg = 'revision not found: %s' % err.name
            return tmpl('error', error=msg)
示例#25
0
    def run_wsgi(self, req):

        self.refresh(req)

        # work with CGI variables to create coherent structure
        # use SCRIPT_NAME, PATH_INFO and QUERY_STRING as well as our REPO_NAME

        req.url = req.env['SCRIPT_NAME']
        if not req.url.endswith('/'):
            req.url += '/'
        if 'REPO_NAME' in req.env:
            req.url += req.env['REPO_NAME'] + '/'

        if 'PATH_INFO' in req.env:
            parts = req.env['PATH_INFO'].strip('/').split('/')
            repo_parts = req.env.get('REPO_NAME', '').split('/')
            if parts[:len(repo_parts)] == repo_parts:
                parts = parts[len(repo_parts):]
            query = '/'.join(parts)
        else:
            query = req.env['QUERY_STRING'].split('&', 1)[0]
            query = query.split(';', 1)[0]

        # process this if it's a protocol request
        # protocol bits don't need to create any URLs
        # and the clients always use the old URL structure

        cmd = req.form.get('cmd', [''])[0]
        if protocol.iscmd(cmd):
            try:
                if query:
                    raise ErrorResponse(HTTP_NOT_FOUND)
                if cmd in perms:
                    self.check_perm(req, perms[cmd])
                return protocol.call(self.repo, req, cmd)
            except ErrorResponse as inst:
                # A client that sends unbundle without 100-continue will
                # break if we respond early.
                if (cmd == 'unbundle' and
                    (req.env.get('HTTP_EXPECT',
                                 '').lower() != '100-continue') or
                    req.env.get('X-HgHttp2', '')):
                    req.drain()
                else:
                    req.headers.append(('Connection', 'Close'))
                req.respond(inst, protocol.HGTYPE,
                            body='0\n%s\n' % inst.message)
                return ''

        # translate user-visible url structure to internal structure

        args = query.split('/', 2)
        if 'cmd' not in req.form and args and args[0]:

            cmd = args.pop(0)
            style = cmd.rfind('-')
            if style != -1:
                req.form['style'] = [cmd[:style]]
                cmd = cmd[style + 1:]

            # avoid accepting e.g. style parameter as command
            if util.safehasattr(webcommands, cmd):
                req.form['cmd'] = [cmd]

            if cmd == 'static':
                req.form['file'] = ['/'.join(args)]
            else:
                if args and args[0]:
                    node = args.pop(0)
                    req.form['node'] = [node]
                if args:
                    req.form['file'] = args

            ua = req.env.get('HTTP_USER_AGENT', '')
            if cmd == 'rev' and 'mercurial' in ua:
                req.form['style'] = ['raw']

            if cmd == 'archive':
                fn = req.form['node'][0]
                for type_, spec in self.archive_specs.iteritems():
                    ext = spec[2]
                    if fn.endswith(ext):
                        req.form['node'] = [fn[:-len(ext)]]
                        req.form['type'] = [type_]

        # process the web interface request

        try:
            tmpl = self.templater(req)
            ctype = tmpl('mimetype', encoding=encoding.encoding)
            ctype = templater.stringify(ctype)

            # check read permissions non-static content
            if cmd != 'static':
                self.check_perm(req, None)

            if cmd == '':
                req.form['cmd'] = [tmpl.cache['default']]
                cmd = req.form['cmd'][0]

            if self.configbool('web', 'cache', True):
                caching(self, req) # sets ETag header or raises NOT_MODIFIED
            if cmd not in webcommands.__all__:
                msg = 'no such method: %s' % cmd
                raise ErrorResponse(HTTP_BAD_REQUEST, msg)
            elif cmd == 'file' and 'raw' in req.form.get('style', []):
                self.ctype = ctype
                content = webcommands.rawfile(self, req, tmpl)
            else:
                content = getattr(webcommands, cmd)(self, req, tmpl)
                req.respond(HTTP_OK, ctype)

            return content

        except (error.LookupError, error.RepoLookupError) as err:
            req.respond(HTTP_NOT_FOUND, ctype)
            msg = str(err)
            if (util.safehasattr(err, 'name') and
                not isinstance(err,  error.ManifestLookupError)):
                msg = 'revision not found: %s' % err.name
            return tmpl('error', error=msg)
        except (error.RepoError, error.RevlogError) as inst:
            req.respond(HTTP_SERVER_ERROR, ctype)
            return tmpl('error', error=str(inst))
        except ErrorResponse as inst:
            req.respond(inst, ctype)
            if inst.code == HTTP_NOT_MODIFIED:
                # Not allowed to return a body on a 304
                return ['']
            return tmpl('error', error=inst.message)