##// END OF EJS Templates
wireproto: syntax for encoding CBOR into frames...
Gregory Szorc -
r37306:cc5a040f default
parent child Browse files
Show More
@@ -2793,7 +2793,10 b' def debugwireproto(ui, repo, path=None, '
2793 2793 or a flag name for stream flags or frame flags, respectively. Values are
2794 2794 resolved to integers and then bitwise OR'd together.
2795 2795
2796 ``payload`` is is evaluated as a Python byte string literal.
2796 ``payload`` represents the raw frame payload. If it begins with
2797 ``cbor:``, the following string is evaluated as Python code and the
2798 resulting object is fed into a CBOR encoder. Otherwise it is interpreted
2799 as a Python byte string literal.
2797 2800 """
2798 2801 opts = pycompat.byteskwargs(opts)
2799 2802
@@ -9,6 +9,7 b''
9 9
10 10 from __future__ import absolute_import
11 11
12 import __future__
12 13 import codecs
13 14 import re as remod
14 15 import textwrap
@@ -497,3 +498,29 b' def parsebool(s):'
497 498 If s is not a valid boolean, returns None.
498 499 """
499 500 return _booleans.get(s.lower(), None)
501
502 def evalpython(s):
503 """Evaluate a string containing a Python expression.
504
505 THIS FUNCTION IS NOT SAFE TO USE ON UNTRUSTED INPUT. IT'S USE SHOULD BE
506 LIMITED TO DEVELOPER-FACING FUNCTIONALITY.
507 """
508 globs = {
509 r'__builtins__': {
510 r'None': None,
511 r'False': False,
512 r'True': True,
513 r'int': int,
514 r'set': set,
515 r'tuple': tuple,
516 # Don't need to expose dict and list because we can use
517 # literals.
518 },
519 }
520
521 # We can't use eval() directly because it inherits compiler
522 # flags from this module and we need unicode literals for Python 3
523 # compatibility.
524 code = compile(s, r'<string>', r'eval',
525 __future__.unicode_literals.compiler_flag, True)
526 return eval(code, globs, {})
@@ -16,6 +16,7 b' import struct'
16 16 from .i18n import _
17 17 from .thirdparty import (
18 18 attr,
19 cbor,
19 20 )
20 21 from . import (
21 22 error,
@@ -156,6 +157,9 b' def makeframe(requestid, streamid, strea'
156 157 def makeframefromhumanstring(s):
157 158 """Create a frame from a human readable string
158 159
160 DANGER: NOT SAFE TO USE WITH UNTRUSTED INPUT BECAUSE OF POTENTIAL
161 eval() USAGE. DO NOT USE IN CORE.
162
159 163 Strings have the form:
160 164
161 165 <request-id> <stream-id> <stream-flags> <type> <flags> <payload>
@@ -169,6 +173,11 b' def makeframefromhumanstring(s):'
169 173 named constant.
170 174
171 175 Flags can be delimited by `|` to bitwise OR them together.
176
177 If the payload begins with ``cbor:``, the following string will be
178 evaluated as Python code and the resulting object will be fed into
179 a CBOR encoder. Otherwise, the payload is interpreted as a Python
180 byte string literal.
172 181 """
173 182 fields = s.split(b' ', 5)
174 183 requestid, streamid, streamflags, frametype, frameflags, payload = fields
@@ -196,7 +205,11 b' def makeframefromhumanstring(s):'
196 205 else:
197 206 finalflags |= int(flag)
198 207
199 payload = stringutil.unescapestr(payload)
208 if payload.startswith(b'cbor:'):
209 payload = cbor.dumps(stringutil.evalpython(payload[5:]), canonical=True)
210
211 else:
212 payload = stringutil.unescapestr(payload)
200 213
201 214 return makeframe(requestid=requestid, streamid=streamid,
202 215 streamflags=finalstreamflags, typeid=frametype,
@@ -35,6 +35,59 b' def sendcommandframes(reactor, stream, r'
35 35 framing.createcommandframes(stream, rid, cmd, args,
36 36 datafh))
37 37
38 class FrameHumanStringTests(unittest.TestCase):
39 def testbasic(self):
40 self.assertEqual(ffs(b'1 1 0 1 0 '),
41 b'\x00\x00\x00\x01\x00\x01\x00\x10')
42
43 self.assertEqual(ffs(b'2 4 0 1 0 '),
44 b'\x00\x00\x00\x02\x00\x04\x00\x10')
45
46 self.assertEqual(ffs(b'2 4 0 1 0 foo'),
47 b'\x03\x00\x00\x02\x00\x04\x00\x10foo')
48
49 def testcborint(self):
50 self.assertEqual(ffs(b'1 1 0 1 0 cbor:15'),
51 b'\x01\x00\x00\x01\x00\x01\x00\x10\x0f')
52
53 self.assertEqual(ffs(b'1 1 0 1 0 cbor:42'),
54 b'\x02\x00\x00\x01\x00\x01\x00\x10\x18*')
55
56 self.assertEqual(ffs(b'1 1 0 1 0 cbor:1048576'),
57 b'\x05\x00\x00\x01\x00\x01\x00\x10\x1a'
58 b'\x00\x10\x00\x00')
59
60 self.assertEqual(ffs(b'1 1 0 1 0 cbor:0'),
61 b'\x01\x00\x00\x01\x00\x01\x00\x10\x00')
62
63 self.assertEqual(ffs(b'1 1 0 1 0 cbor:-1'),
64 b'\x01\x00\x00\x01\x00\x01\x00\x10 ')
65
66 self.assertEqual(ffs(b'1 1 0 1 0 cbor:-342542'),
67 b'\x05\x00\x00\x01\x00\x01\x00\x10:\x00\x05:\r')
68
69 def testcborstrings(self):
70 # String literals should be unicode.
71 self.assertEqual(ffs(b"1 1 0 1 0 cbor:'foo'"),
72 b'\x04\x00\x00\x01\x00\x01\x00\x10cfoo')
73
74 self.assertEqual(ffs(b"1 1 0 1 0 cbor:b'foo'"),
75 b'\x04\x00\x00\x01\x00\x01\x00\x10Cfoo')
76
77 self.assertEqual(ffs(b"1 1 0 1 0 cbor:u'foo'"),
78 b'\x04\x00\x00\x01\x00\x01\x00\x10cfoo')
79
80 def testcborlists(self):
81 self.assertEqual(ffs(b"1 1 0 1 0 cbor:[None, True, False, 42, b'foo']"),
82 b'\n\x00\x00\x01\x00\x01\x00\x10\x85\xf6\xf5\xf4'
83 b'\x18*Cfoo')
84
85 def testcbordicts(self):
86 self.assertEqual(ffs(b"1 1 0 1 0 "
87 b"cbor:{b'foo': b'val1', b'bar': b'val2'}"),
88 b'\x13\x00\x00\x01\x00\x01\x00\x10\xa2'
89 b'CbarDval2CfooDval1')
90
38 91 class FrameTests(unittest.TestCase):
39 92 def testdataexactframesize(self):
40 93 data = util.bytesio(b'x' * framing.DEFAULT_MAX_FRAME_SIZE)
General Comments 0
You need to be logged in to leave comments. Login now