mirror of
https://github.com/facebook/sapling.git
synced 2024-10-07 23:38:50 +03:00
hgweb: all protocol functions have become generators
Using the write() callable supplied by the start_response() call is frowned upon by the WSGI spec, returning an iterable over the content chunks is the recommended way. Be aware, though: returning many small chunks will slow down responses, because the server has to flush each chunk separately.
This commit is contained in:
parent
b79ad5315b
commit
d50a34e7a6
@ -76,8 +76,7 @@ class hgweb(object):
|
||||
|
||||
def __call__(self, env, respond):
|
||||
req = wsgirequest(env, respond)
|
||||
self.run_wsgi(req)
|
||||
return req
|
||||
return self.run_wsgi(req)
|
||||
|
||||
def run_wsgi(self, req):
|
||||
|
||||
@ -90,10 +89,9 @@ class hgweb(object):
|
||||
cmd = req.form.get('cmd', [''])[0]
|
||||
if cmd and cmd in protocol.__all__:
|
||||
if cmd in perms and not self.check_perm(req, perms[cmd]):
|
||||
return
|
||||
return []
|
||||
method = getattr(protocol, cmd)
|
||||
method(self.repo, req)
|
||||
return
|
||||
return method(self.repo, req)
|
||||
|
||||
# work with CGI variables to create coherent structure
|
||||
# use SCRIPT_NAME, PATH_INFO and QUERY_STRING as well as our REPO_NAME
|
||||
@ -171,6 +169,7 @@ class hgweb(object):
|
||||
|
||||
req.write(content)
|
||||
del tmpl
|
||||
return req
|
||||
|
||||
except revlog.LookupError, err:
|
||||
req.respond(HTTP_NOT_FOUND, ctype)
|
||||
|
@ -30,12 +30,12 @@ def lookup(repo, req):
|
||||
success = 0
|
||||
resp = "%s %s\n" % (success, r)
|
||||
req.respond(HTTP_OK, HGTYPE, length=len(resp))
|
||||
req.write(resp)
|
||||
yield resp
|
||||
|
||||
def heads(repo, req):
|
||||
resp = " ".join(map(hex, repo.heads())) + "\n"
|
||||
req.respond(HTTP_OK, HGTYPE, length=len(resp))
|
||||
req.write(resp)
|
||||
yield resp
|
||||
|
||||
def branches(repo, req):
|
||||
nodes = []
|
||||
@ -46,7 +46,7 @@ def branches(repo, req):
|
||||
resp.write(" ".join(map(hex, b)) + "\n")
|
||||
resp = resp.getvalue()
|
||||
req.respond(HTTP_OK, HGTYPE, length=len(resp))
|
||||
req.write(resp)
|
||||
yield resp
|
||||
|
||||
def between(repo, req):
|
||||
if 'pairs' in req.form:
|
||||
@ -57,7 +57,7 @@ def between(repo, req):
|
||||
resp.write(" ".join(map(hex, b)) + "\n")
|
||||
resp = resp.getvalue()
|
||||
req.respond(HTTP_OK, HGTYPE, length=len(resp))
|
||||
req.write(resp)
|
||||
yield resp
|
||||
|
||||
def changegroup(repo, req):
|
||||
req.respond(HTTP_OK, HGTYPE)
|
||||
@ -72,9 +72,9 @@ def changegroup(repo, req):
|
||||
chunk = f.read(4096)
|
||||
if not chunk:
|
||||
break
|
||||
req.write(z.compress(chunk))
|
||||
yield z.compress(chunk)
|
||||
|
||||
req.write(z.flush())
|
||||
yield z.flush()
|
||||
|
||||
def changegroupsubset(repo, req):
|
||||
req.respond(HTTP_OK, HGTYPE)
|
||||
@ -92,9 +92,9 @@ def changegroupsubset(repo, req):
|
||||
chunk = f.read(4096)
|
||||
if not chunk:
|
||||
break
|
||||
req.write(z.compress(chunk))
|
||||
yield z.compress(chunk)
|
||||
|
||||
req.write(z.flush())
|
||||
yield z.flush()
|
||||
|
||||
def capabilities(repo, req):
|
||||
caps = ['lookup', 'changegroupsubset']
|
||||
@ -104,23 +104,11 @@ def capabilities(repo, req):
|
||||
caps.append('unbundle=%s' % ','.join(changegroupmod.bundlepriority))
|
||||
rsp = ' '.join(caps)
|
||||
req.respond(HTTP_OK, HGTYPE, length=len(rsp))
|
||||
req.write(rsp)
|
||||
yield rsp
|
||||
|
||||
def unbundle(repo, req):
|
||||
|
||||
def bail(response, headers={}):
|
||||
length = int(req.env.get('CONTENT_LENGTH', 0))
|
||||
for s in util.filechunkiter(req, limit=length):
|
||||
# drain incoming bundle, else client will not see
|
||||
# response when run outside cgi script
|
||||
pass
|
||||
|
||||
status = headers.pop('status', HTTP_OK)
|
||||
req.header(headers.items())
|
||||
req.respond(status, HGTYPE)
|
||||
req.write('0\n')
|
||||
req.write(response)
|
||||
|
||||
errorfmt = '0\n%s\n'
|
||||
proto = req.env.get('wsgi.url_scheme') or 'http'
|
||||
their_heads = req.form['heads'][0].split(' ')
|
||||
|
||||
@ -130,7 +118,13 @@ def unbundle(repo, req):
|
||||
|
||||
# fail early if possible
|
||||
if not check_heads():
|
||||
bail('unsynced changes\n')
|
||||
length = int(req.env.get('CONTENT_LENGTH', 0))
|
||||
for s in util.filechunkiter(req, limit=length):
|
||||
# drain incoming bundle, else client will not see
|
||||
# response when run outside cgi script
|
||||
pass
|
||||
req.respond(HTTP_OK, HGTYPE)
|
||||
yield errorfmt % 'unsynced changes'
|
||||
return
|
||||
|
||||
req.respond(HTTP_OK, HGTYPE)
|
||||
@ -149,8 +143,7 @@ def unbundle(repo, req):
|
||||
lock = repo.lock()
|
||||
try:
|
||||
if not check_heads():
|
||||
req.write('0\n')
|
||||
req.write('unsynced changes\n')
|
||||
yield errorfmt % 'unsynced changes'
|
||||
return
|
||||
|
||||
fp.seek(0)
|
||||
@ -177,15 +170,12 @@ def unbundle(repo, req):
|
||||
finally:
|
||||
val = sys.stdout.getvalue()
|
||||
sys.stdout, sys.stderr = oldio
|
||||
req.write('%d\n' % ret)
|
||||
req.write(val)
|
||||
yield '%d\n%s' % (ret, val)
|
||||
finally:
|
||||
del lock
|
||||
except ValueError, inst:
|
||||
req.write('0\n')
|
||||
req.write(str(inst) + '\n')
|
||||
yield errorfmt % inst
|
||||
except (OSError, IOError), inst:
|
||||
req.write('0\n')
|
||||
filename = getattr(inst, 'filename', '')
|
||||
# Don't send our filesystem layout to the client
|
||||
if filename.startswith(repo.root):
|
||||
@ -198,12 +188,11 @@ def unbundle(repo, req):
|
||||
else:
|
||||
code = HTTP_SERVER_ERROR
|
||||
req.respond(code)
|
||||
req.write('%s: %s\n' % (error, filename))
|
||||
yield '0\n%s: %s\n' % (error, filename)
|
||||
finally:
|
||||
fp.close()
|
||||
os.unlink(tempname)
|
||||
|
||||
def stream_out(repo, req):
|
||||
req.respond(HTTP_OK, HGTYPE)
|
||||
for chunk in streamclone.stream_out(repo, untrusted=True):
|
||||
req.write(chunk)
|
||||
return streamclone.stream_out(repo, untrusted=True)
|
||||
|
@ -122,7 +122,8 @@ class _hgwebhandler(object, BaseHTTPServer.BaseHTTPRequestHandler):
|
||||
self.saved_headers = []
|
||||
self.sent_headers = False
|
||||
self.length = None
|
||||
self.server.application(env, self._start_response)
|
||||
for chunk in self.server.application(env, self._start_response):
|
||||
self._write(chunk)
|
||||
|
||||
def send_headers(self):
|
||||
if not self.saved_status:
|
||||
|
Loading…
Reference in New Issue
Block a user