protocol.py
133 lines
| 4.0 KiB
| text/x-python
|
PythonLexer
|
r5598 | # | ||
# Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net> | ||||
# Copyright 2005-2007 Matt Mackall <mpm@selenic.com> | ||||
# | ||||
|
r8225 | # This software may be used and distributed according to the terms of the | ||
|
r10263 | # GNU General Public License version 2 or any later version. | ||
|
r5598 | |||
|
r27046 | from __future__ import absolute_import | ||
import cgi | ||||
import zlib | ||||
from .common import ( | ||||
HTTP_OK, | ||||
) | ||||
from .. import ( | ||||
util, | ||||
wireproto, | ||||
) | ||||
|
r28861 | stringio = util.stringio | ||
|
r5963 | |||
|
r28883 | urlerr = util.urlerr | ||
urlreq = util.urlreq | ||||
|
r5993 | HGTYPE = 'application/mercurial-0.1' | ||
|
r15017 | HGERRTYPE = 'application/hg-error' | ||
|
r11595 | |||
|
r20903 | class webproto(wireproto.abstractserverproto): | ||
|
r14614 | def __init__(self, req, ui): | ||
|
r11595 | self.req = req | ||
self.response = '' | ||||
|
r14614 | self.ui = ui | ||
|
r11595 | def getargs(self, args): | ||
|
r14093 | knownargs = self._args() | ||
|
r11595 | data = {} | ||
keys = args.split() | ||||
for k in keys: | ||||
if k == '*': | ||||
star = {} | ||||
|
r14093 | for key in knownargs.keys(): | ||
|
r13721 | if key != 'cmd' and key not in keys: | ||
|
r14093 | star[key] = knownargs[key][0] | ||
|
r11595 | data['*'] = star | ||
else: | ||||
|
r14093 | data[k] = knownargs[k][0] | ||
|
r11595 | return [data[k] for k in keys] | ||
|
r14093 | def _args(self): | ||
args = self.req.form.copy() | ||||
|
r28530 | postlen = int(self.req.env.get('HTTP_X_HGARGS_POST', 0)) | ||
if postlen: | ||||
args.update(cgi.parse_qs( | ||||
self.req.read(postlen), keep_blank_values=True)) | ||||
return args | ||||
|
r14093 | chunks = [] | ||
|
r14094 | i = 1 | ||
|
r14494 | while True: | ||
|
r14094 | h = self.req.env.get('HTTP_X_HGARG_' + str(i)) | ||
|
r14093 | if h is None: | ||
break | ||||
chunks += [h] | ||||
|
r14094 | i += 1 | ||
|
r14093 | args.update(cgi.parse_qs(''.join(chunks), keep_blank_values=True)) | ||
return args | ||||
|
r11621 | def getfile(self, fp): | ||
length = int(self.req.env['CONTENT_LENGTH']) | ||||
for s in util.filechunkiter(self.req, limit=length): | ||||
fp.write(s) | ||||
def redirect(self): | ||||
|
r14614 | self.oldio = self.ui.fout, self.ui.ferr | ||
|
r28861 | self.ui.ferr = self.ui.fout = stringio() | ||
|
r14614 | def restore(self): | ||
val = self.ui.fout.getvalue() | ||||
self.ui.ferr, self.ui.fout = self.oldio | ||||
return val | ||||
|
r30206 | |||
|
r30014 | def groupchunks(self, fh): | ||
|
r30206 | def getchunks(): | ||
while True: | ||||
chunk = fh.read(32768) | ||||
if not chunk: | ||||
break | ||||
yield chunk | ||||
return self.compresschunks(getchunks()) | ||||
def compresschunks(self, chunks): | ||||
|
r29788 | # Don't allow untrusted settings because disabling compression or | ||
# setting a very high compression level could lead to flooding | ||||
# the server's network or CPU. | ||||
|
r29748 | z = zlib.compressobj(self.ui.configint('server', 'zliblevel', -1)) | ||
|
r30206 | for chunk in chunks: | ||
|
r29792 | data = z.compress(chunk) | ||
# Not all calls to compress() emit data. It is cheaper to inspect | ||||
# that here than to send it via the generator. | ||||
if data: | ||||
yield data | ||||
|
r11623 | yield z.flush() | ||
|
r30206 | |||
|
r11595 | def _client(self): | ||
return 'remote:%s:%s:%s' % ( | ||||
self.req.env.get('wsgi.url_scheme') or 'http', | ||||
|
r28883 | urlreq.quote(self.req.env.get('REMOTE_HOST', '')), | ||
urlreq.quote(self.req.env.get('REMOTE_USER', ''))) | ||||
|
r11595 | |||
def iscmd(cmd): | ||||
return cmd in wireproto.commands | ||||
def call(repo, req, cmd): | ||||
|
r14614 | p = webproto(req, repo.ui) | ||
|
r11625 | rsp = wireproto.dispatch(repo, p, cmd) | ||
|
r11626 | if isinstance(rsp, str): | ||
|
r18352 | req.respond(HTTP_OK, HGTYPE, body=rsp) | ||
return [] | ||||
|
r11626 | elif isinstance(rsp, wireproto.streamres): | ||
req.respond(HTTP_OK, HGTYPE) | ||||
return rsp.gen | ||||
elif isinstance(rsp, wireproto.pushres): | ||||
|
r14614 | val = p.restore() | ||
|
r18346 | rsp = '%d\n%s' % (rsp.res, val) | ||
|
r18352 | req.respond(HTTP_OK, HGTYPE, body=rsp) | ||
return [] | ||||
|
r12703 | elif isinstance(rsp, wireproto.pusherr): | ||
|
r12704 | # drain the incoming bundle | ||
req.drain() | ||||
|
r14614 | p.restore() | ||
|
r12703 | rsp = '0\n%s\n' % rsp.res | ||
|
r18352 | req.respond(HTTP_OK, HGTYPE, body=rsp) | ||
return [] | ||||
|
r15017 | elif isinstance(rsp, wireproto.ooberror): | ||
rsp = rsp.message | ||||
|
r18352 | req.respond(HTTP_OK, HGERRTYPE, body=rsp) | ||
return [] | ||||