Mercurial > public > mercurial-scm > hg-stable
diff mercurial/wireprotoframing.py @ 37319:36d17f37db91
wireproto: convert human output frames to CBOR
This is easier than rolling our own encoding format.
As a bonus, some of our artificial limits around lengths of
things went away because we are no longer using fixed length
fields to hold sizes.
Differential Revision: https://phab.mercurial-scm.org/D3067
author | Gregory Szorc <gregory.szorc@gmail.com> |
---|---|
date | Fri, 30 Mar 2018 14:52:32 -0700 |
parents | e9aadee698cf |
children | 2f81926c7f89 |
line wrap: on
line diff
--- a/mercurial/wireprotoframing.py Mon Apr 02 17:06:42 2018 +0530 +++ b/mercurial/wireprotoframing.py Fri Mar 30 14:52:32 2018 -0700 @@ -395,7 +395,8 @@ flags=flags, payload=msg) -def createtextoutputframe(stream, requestid, atoms): +def createtextoutputframe(stream, requestid, atoms, + maxframesize=DEFAULT_MAX_FRAME_SIZE): """Create a text output frame to render text to people. ``atoms`` is a 3-tuple of (formatting string, args, labels). @@ -405,15 +406,9 @@ formatters to be applied at rendering time. In terms of the ``ui`` class, each atom corresponds to a ``ui.write()``. """ - bytesleft = DEFAULT_MAX_FRAME_SIZE - atomchunks = [] + atomdicts = [] for (formatting, args, labels) in atoms: - if len(args) > 255: - raise ValueError('cannot use more than 255 formatting arguments') - if len(labels) > 255: - raise ValueError('cannot use more than 255 labels') - # TODO look for localstr, other types here? if not isinstance(formatting, bytes): @@ -425,8 +420,8 @@ if not isinstance(label, bytes): raise ValueError('must use bytes for labels') - # Formatting string must be UTF-8. - formatting = formatting.decode(r'utf-8', r'replace').encode(r'utf-8') + # Formatting string must be ASCII. + formatting = formatting.decode(r'ascii', r'replace').encode(r'ascii') # Arguments must be UTF-8. args = [a.decode(r'utf-8', r'replace').encode(r'utf-8') for a in args] @@ -435,36 +430,23 @@ labels = [l.decode(r'ascii', r'strict').encode(r'ascii') for l in labels] - if len(formatting) > 65535: - raise ValueError('formatting string cannot be longer than 64k') - - if any(len(a) > 65535 for a in args): - raise ValueError('argument string cannot be longer than 64k') - - if any(len(l) > 255 for l in labels): - raise ValueError('label string cannot be longer than 255 bytes') + atom = {b'msg': formatting} + if args: + atom[b'args'] = args + if labels: + atom[b'labels'] = labels - chunks = [ - struct.pack(r'<H', len(formatting)), - struct.pack(r'<BB', len(labels), len(args)), - struct.pack(r'<' + r'B' * len(labels), *map(len, labels)), - struct.pack(r'<' + r'H' * len(args), *map(len, args)), - ] - chunks.append(formatting) - chunks.extend(labels) - chunks.extend(args) + atomdicts.append(atom) - atom = b''.join(chunks) - atomchunks.append(atom) - bytesleft -= len(atom) + payload = cbor.dumps(atomdicts, canonical=True) - if bytesleft < 0: + if len(payload) > maxframesize: raise ValueError('cannot encode data in a single frame') yield stream.makeframe(requestid=requestid, typeid=FRAME_TYPE_TEXT_OUTPUT, flags=0, - payload=b''.join(atomchunks)) + payload=payload) class stream(object): """Represents a logical unidirectional series of frames."""