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."""