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))
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))
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
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
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
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))
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)
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)
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)
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)
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))
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))
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 "")
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))
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))
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)
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)
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)
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))
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
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
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))
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)
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)