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 process_request(self, request): """ Process the request object and returns output. """ protocol = mercurial.hgweb.protocol request.stdin.seek(0) env = dict(request.environ) # the request object *should* be WSGI compliant as Mercurial # supports it, but we have kind of completely wrap around it so # might as well emulate it if it's missing. if 'wsgi.version' not in env: # 'REQUEST_URI' is missing but seems to be unused env['REMOTE_HOST'] = env['REMOTE_ADDR'] # emulate wsgi environment env['wsgi.version'] = (1, 0) # environment variable has https env['wsgi.url_scheme'] = \ request.base.split(':')[0] # self.url_scheme env['wsgi.input'] = request.stdin # self.rfile env['wsgi.errors'] = StringIO() #_error_logger(self) env['wsgi.multithread'] = True # XXX guess env['wsgi.multiprocess'] = True # same as above env['wsgi.run_once'] = True headers_set = [] headers_sent = [] def write(data): if not headers_set: raise AssertionError("write() before start_response()") elif not headers_sent: # Before the first output, send the stored headers status, response_headers = headers_sent[:] = headers_set status, code = status.split(' ', 1) request.response.setStatus(status, code) for header in response_headers: # let zope deal with the header. request.response.setHeader(*header) out.write(data) out.flush() def start_response(status, response_headers, exc_info=None): if exc_info: try: if headers_sent: # Re-raise original exception if headers sent raise exc_info[0], exc_info[1], exc_info[2] finally: exc_info = None # avoid dangling circular ref elif headers_set: raise AssertionError("Headers already set!") headers_set[:] = [status, response_headers] return write # XXX this is a hgweb object already. While run_wsgi has what # we need, Zope/repoze/Plone handles some of the request stuff # already, so we just skip some of the parsing steps. out = StringIO() req = wsgirequest(env, start_response) self.refresh() 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 cmd: if not protocol.iscmd(cmd): raise UnsupportedCommandError('%s is unsupported' % cmd) # XXX not sure why? #if query: # raise ErrorResponse(HTTP_NOT_FOUND) try: if cmd in perms: try: self.check_perm(req, perms[cmd]) except ErrorResponse, inst: if cmd == 'unbundle': req.drain() raise content = protocol.call(self.repo, req, cmd) except ErrorResponse, inst: req.respond(inst, protocol.HGTYPE) # XXX doing write here because the other methods expect # output. write('0\n') if not inst.message: return [] write('%s\n' % inst.message,) return out.getvalue()