##// END OF EJS Templates
minifileset: note the unsupported file pattern when raising a parse error...
minifileset: note the unsupported file pattern when raising a parse error This was useful in debugging, because I stupidly quoted it out of habit from the command line. This isn't a great example that clearly shows the problem, but I don't know how to improve it. The problem *is* obvious once a complex statement or a clearly bogus string is used.

File last commit:

r35768:a39a9df7 default
r35818:d5288b96 stable
Show More
protocol.py
201 lines | 6.6 KiB | text/x-python | PythonLexer
Dirkjan Ochtman
separate the wire protocol commands from the user interface commands
r5598 #
# Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
# Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
#
Martin Geisler
updated license to be explicit about GPL version 2
r8225 # This software may be used and distributed according to the terms of the
Matt Mackall
Update license to GPLv2+
r10263 # GNU General Public License version 2 or any later version.
Dirkjan Ochtman
separate the wire protocol commands from the user interface commands
r5598
Yuya Nishihara
hgweb: use absolute_import
r27046 from __future__ import absolute_import
import cgi
Gregory Szorc
protocol: send application/mercurial-0.2 responses to capable clients...
r30764 import struct
Yuya Nishihara
hgweb: use absolute_import
r27046
from .common import (
HTTP_OK,
)
from .. import (
Augie Fackler
hgweb: in protocol adapter, avoid control reaching end of non-void function...
r34510 error,
Augie Fackler
hgweb: when unpacking args from request form, convert to bytes...
r34743 pycompat,
Yuya Nishihara
hgweb: use absolute_import
r27046 util,
wireproto,
)
timeless
pycompat: switch to util.stringio for py3 compat
r28861 stringio = util.stringio
Dirkjan Ochtman
hgweb: explicitly check if requested command exists
r5963
timeless
pycompat: switch to util.urlreq/util.urlerr for py3 compat
r28883 urlerr = util.urlerr
urlreq = util.urlreq
Dirkjan Ochtman
hgweb: explicit response status
r5993 HGTYPE = 'application/mercurial-0.1'
Gregory Szorc
protocol: send application/mercurial-0.2 responses to capable clients...
r30764 HGTYPE2 = 'application/mercurial-0.2'
Andrew Pritchard
wireproto: add out-of-band error class to allow remote repo to report errors...
r15017 HGERRTYPE = 'application/hg-error'
Matt Mackall
protocol: move hgweb protocol support back into protocol.py...
r11595
Gregory Szorc
httppeer: extract code for HTTP header spanning...
r30759 def decodevaluefromheaders(req, headerprefix):
Augie Fackler
hgweb: fix decodevaluefromheaders to always return a bytes value...
r34745 """Decode a long value from multiple HTTP request headers.
Returns the value as a bytes, not a str.
"""
Gregory Szorc
httppeer: extract code for HTTP header spanning...
r30759 chunks = []
i = 1
Augie Fackler
hgweb: fix decodevaluefromheaders to always return a bytes value...
r34745 prefix = headerprefix.upper().replace(r'-', r'_')
Gregory Szorc
httppeer: extract code for HTTP header spanning...
r30759 while True:
Augie Fackler
hgweb: fix decodevaluefromheaders to always return a bytes value...
r34745 v = req.env.get(r'HTTP_%s_%d' % (prefix, i))
Gregory Szorc
httppeer: extract code for HTTP header spanning...
r30759 if v is None:
break
Augie Fackler
hgweb: fix decodevaluefromheaders to always return a bytes value...
r34745 chunks.append(pycompat.bytesurl(v))
Gregory Szorc
httppeer: extract code for HTTP header spanning...
r30759 i += 1
return ''.join(chunks)
Pierre-Yves David
wireproto: introduce an abstractserverproto class...
r20903 class webproto(wireproto.abstractserverproto):
Idan Kamara
ui: use I/O descriptors internally...
r14614 def __init__(self, req, ui):
Matt Mackall
protocol: move hgweb protocol support back into protocol.py...
r11595 self.req = req
self.response = ''
Idan Kamara
ui: use I/O descriptors internally...
r14614 self.ui = ui
Gregory Szorc
protocol: declare transport protocol name...
r30562 self.name = 'http'
Matt Mackall
protocol: move hgweb protocol support back into protocol.py...
r11595 def getargs(self, args):
Steven Brown
httprepo: long arguments support (issue2126)...
r14093 knownargs = self._args()
Matt Mackall
protocol: move hgweb protocol support back into protocol.py...
r11595 data = {}
keys = args.split()
for k in keys:
if k == '*':
star = {}
Steven Brown
httprepo: long arguments support (issue2126)...
r14093 for key in knownargs.keys():
Peter Arrenbrecht
wireproto: fix handling of '*' args for HTTP and SSH
r13721 if key != 'cmd' and key not in keys:
Steven Brown
httprepo: long arguments support (issue2126)...
r14093 star[key] = knownargs[key][0]
Matt Mackall
protocol: move hgweb protocol support back into protocol.py...
r11595 data['*'] = star
else:
Steven Brown
httprepo: long arguments support (issue2126)...
r14093 data[k] = knownargs[k][0]
Matt Mackall
protocol: move hgweb protocol support back into protocol.py...
r11595 return [data[k] for k in keys]
Steven Brown
httprepo: long arguments support (issue2126)...
r14093 def _args(self):
args = self.req.form.copy()
Augie Fackler
hgweb: when unpacking args from request form, convert to bytes...
r34743 if pycompat.ispy3:
args = {k.encode('ascii'): [v.encode('ascii') for v in vs]
for k, vs in args.items()}
Augie Fackler
hgweb: more "headers are native strs" cleanup...
r34744 postlen = int(self.req.env.get(r'HTTP_X_HGARGS_POST', 0))
Augie Fackler
http: support sending hgargs via POST body instead of in GET or headers...
r28530 if postlen:
args.update(cgi.parse_qs(
self.req.read(postlen), keep_blank_values=True))
return args
Gregory Szorc
httppeer: extract code for HTTP header spanning...
r30759
Augie Fackler
hgweb: more "headers are native strs" cleanup...
r34744 argvalue = decodevaluefromheaders(self.req, r'X-HgArg')
Gregory Szorc
httppeer: extract code for HTTP header spanning...
r30759 args.update(cgi.parse_qs(argvalue, keep_blank_values=True))
Steven Brown
httprepo: long arguments support (issue2126)...
r14093 return args
Dirkjan Ochtman
protocol: shuffle server methods to group send methods
r11621 def getfile(self, fp):
Augie Fackler
hgweb: more "http headers are native strs" cleanup...
r34741 length = int(self.req.env[r'CONTENT_LENGTH'])
Augie Fackler
httppeer: add support for httppostargs when we're sending a file...
r33820 # If httppostargs is used, we need to read Content-Length
# minus the amount that was consumed by args.
Augie Fackler
hgweb: more "http headers are native strs" cleanup...
r34741 length -= int(self.req.env.get(r'HTTP_X_HGARGS_POST', 0))
Dirkjan Ochtman
protocol: shuffle server methods to group send methods
r11621 for s in util.filechunkiter(self.req, limit=length):
fp.write(s)
def redirect(self):
Idan Kamara
ui: use I/O descriptors internally...
r14614 self.oldio = self.ui.fout, self.ui.ferr
timeless
pycompat: switch to util.stringio for py3 compat
r28861 self.ui.ferr = self.ui.fout = stringio()
Idan Kamara
ui: use I/O descriptors internally...
r14614 def restore(self):
val = self.ui.fout.getvalue()
self.ui.ferr, self.ui.fout = self.oldio
return val
Gregory Szorc
wireproto: compress data from a generator...
r30206
Matt Mackall
protocol: move hgweb protocol support back into protocol.py...
r11595 def _client(self):
return 'remote:%s:%s:%s' % (
self.req.env.get('wsgi.url_scheme') or 'http',
timeless
pycompat: switch to util.urlreq/util.urlerr for py3 compat
r28883 urlreq.quote(self.req.env.get('REMOTE_HOST', '')),
urlreq.quote(self.req.env.get('REMOTE_USER', '')))
Matt Mackall
protocol: move hgweb protocol support back into protocol.py...
r11595
Joerg Sonnenberger
wireproto: split streamres into legacy and modern case...
r35768 def responsetype(self, prefer_uncompressed):
Gregory Szorc
protocol: send application/mercurial-0.2 responses to capable clients...
r30764 """Determine the appropriate response type and compression settings.
Returns a tuple of (mediatype, compengine, engineopts).
"""
# Determine the response media type and compression engine based
# on the request parameters.
Augie Fackler
hgweb: more "headers are native strs" cleanup...
r34744 protocaps = decodevaluefromheaders(self.req, r'X-HgProto').split(' ')
Gregory Szorc
protocol: send application/mercurial-0.2 responses to capable clients...
r30764
if '0.2' in protocaps:
Joerg Sonnenberger
wireproto: split streamres into legacy and modern case...
r35768 # All clients are expected to support uncompressed data.
if prefer_uncompressed:
return HGTYPE2, util._noopengine(), {}
Gregory Szorc
protocol: send application/mercurial-0.2 responses to capable clients...
r30764 # Default as defined by wire protocol spec.
compformats = ['zlib', 'none']
for cap in protocaps:
if cap.startswith('comp='):
compformats = cap[5:].split(',')
break
# Now find an agreed upon compression format.
for engine in wireproto.supportedcompengines(self.ui, self,
util.SERVERROLE):
if engine.wireprotosupport().name in compformats:
opts = {}
level = self.ui.configint('server',
'%slevel' % engine.name())
if level is not None:
opts['level'] = level
return HGTYPE2, engine, opts
# No mutually supported compression format. Fall back to the
# legacy protocol.
# 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.
configitems: register the 'server.zliblevel' config
r33225 opts = {'level': self.ui.configint('server', 'zliblevel')}
Gregory Szorc
protocol: send application/mercurial-0.2 responses to capable clients...
r30764 return HGTYPE, util.compengines['zlib'], opts
Matt Mackall
protocol: move hgweb protocol support back into protocol.py...
r11595 def iscmd(cmd):
return cmd in wireproto.commands
def call(repo, req, cmd):
Idan Kamara
ui: use I/O descriptors internally...
r14614 p = webproto(req, repo.ui)
Gregory Szorc
protocol: send application/mercurial-0.2 responses to capable clients...
r30764
Joerg Sonnenberger
wireproto: split streamres into legacy and modern case...
r35768 def genversion2(gen, engine, engineopts):
Gregory Szorc
protocol: send application/mercurial-0.2 responses to capable clients...
r30764 # application/mercurial-0.2 always sends a payload header
# identifying the compression engine.
name = engine.wireprotosupport().name
assert 0 < len(name) < 256
yield struct.pack('B', len(name))
yield name
Joerg Sonnenberger
wireproto: split streamres into legacy and modern case...
r35768 for chunk in gen:
yield chunk
Gregory Szorc
protocol: send application/mercurial-0.2 responses to capable clients...
r30764
Dirkjan Ochtman
protocol: wrap non-string protocol responses in classes
r11625 rsp = wireproto.dispatch(repo, p, cmd)
Augie Fackler
hgweb: in protocol adapter, look for bytes instances, not str...
r34511 if isinstance(rsp, bytes):
Mads Kiilerich
hgweb: pass the actual response body to request.response, not just the length...
r18352 req.respond(HTTP_OK, HGTYPE, body=rsp)
return []
Joerg Sonnenberger
wireproto: split streamres into legacy and modern case...
r35768 elif isinstance(rsp, wireproto.streamres_legacy):
gen = rsp.gen
req.respond(HTTP_OK, HGTYPE)
return gen
Dirkjan Ochtman
protocol: use generators instead of req.write() for hgweb stream responses
r11626 elif isinstance(rsp, wireproto.streamres):
Gregory Szorc
wireproto: drop support for reader interface from streamres (API)...
r35723 gen = rsp.gen
Gregory Szorc
wireproto: perform chunking and compression at protocol layer (API)...
r30466
Gregory Szorc
protocol: send application/mercurial-0.2 responses to capable clients...
r30764 # This code for compression should not be streamres specific. It
# is here because we only compress streamres at the moment.
Joerg Sonnenberger
wireproto: split streamres into legacy and modern case...
r35768 mediatype, engine, engineopts = p.responsetype(rsp.prefer_uncompressed)
gen = engine.compressstream(gen, engineopts)
Gregory Szorc
wireproto: perform chunking and compression at protocol layer (API)...
r30466
Joerg Sonnenberger
wireproto: split streamres into legacy and modern case...
r35768 if mediatype == HGTYPE2:
gen = genversion2(gen, engine, engineopts)
Gregory Szorc
protocol: send application/mercurial-0.2 responses to capable clients...
r30764
req.respond(HTTP_OK, mediatype)
Gregory Szorc
wireproto: perform chunking and compression at protocol layer (API)...
r30466 return gen
Dirkjan Ochtman
protocol: use generators instead of req.write() for hgweb stream responses
r11626 elif isinstance(rsp, wireproto.pushres):
Idan Kamara
ui: use I/O descriptors internally...
r14614 val = p.restore()
Mads Kiilerich
hgweb: use Content-Length for pushres...
r18346 rsp = '%d\n%s' % (rsp.res, val)
Mads Kiilerich
hgweb: pass the actual response body to request.response, not just the length...
r18352 req.respond(HTTP_OK, HGTYPE, body=rsp)
return []
Benoit Boissinot
wireproto: introduce pusherr() to deal with "unsynced changes" error...
r12703 elif isinstance(rsp, wireproto.pusherr):
Benoit Boissinot
wireproto/http: drain the incoming bundle in case of errors
r12704 # drain the incoming bundle
req.drain()
Idan Kamara
ui: use I/O descriptors internally...
r14614 p.restore()
Benoit Boissinot
wireproto: introduce pusherr() to deal with "unsynced changes" error...
r12703 rsp = '0\n%s\n' % rsp.res
Mads Kiilerich
hgweb: pass the actual response body to request.response, not just the length...
r18352 req.respond(HTTP_OK, HGTYPE, body=rsp)
return []
Andrew Pritchard
wireproto: add out-of-band error class to allow remote repo to report errors...
r15017 elif isinstance(rsp, wireproto.ooberror):
rsp = rsp.message
Mads Kiilerich
hgweb: pass the actual response body to request.response, not just the length...
r18352 req.respond(HTTP_OK, HGERRTYPE, body=rsp)
return []
Augie Fackler
hgweb: in protocol adapter, avoid control reaching end of non-void function...
r34510 raise error.ProgrammingError('hgweb.protocol internal failure', rsp)