##// 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 or a flag name for stream flags or frame flags, respectively. Values are
2793 or a flag name for stream flags or frame flags, respectively. Values are
2794 resolved to integers and then bitwise OR'd together.
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 opts = pycompat.byteskwargs(opts)
2801 opts = pycompat.byteskwargs(opts)
2799
2802
@@ -9,6 +9,7 b''
9
9
10 from __future__ import absolute_import
10 from __future__ import absolute_import
11
11
12 import __future__
12 import codecs
13 import codecs
13 import re as remod
14 import re as remod
14 import textwrap
15 import textwrap
@@ -497,3 +498,29 b' def parsebool(s):'
497 If s is not a valid boolean, returns None.
498 If s is not a valid boolean, returns None.
498 """
499 """
499 return _booleans.get(s.lower(), None)
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 from .i18n import _
16 from .i18n import _
17 from .thirdparty import (
17 from .thirdparty import (
18 attr,
18 attr,
19 cbor,
19 )
20 )
20 from . import (
21 from . import (
21 error,
22 error,
@@ -156,6 +157,9 b' def makeframe(requestid, streamid, strea'
156 def makeframefromhumanstring(s):
157 def makeframefromhumanstring(s):
157 """Create a frame from a human readable string
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 Strings have the form:
163 Strings have the form:
160
164
161 <request-id> <stream-id> <stream-flags> <type> <flags> <payload>
165 <request-id> <stream-id> <stream-flags> <type> <flags> <payload>
@@ -169,6 +173,11 b' def makeframefromhumanstring(s):'
169 named constant.
173 named constant.
170
174
171 Flags can be delimited by `|` to bitwise OR them together.
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 fields = s.split(b' ', 5)
182 fields = s.split(b' ', 5)
174 requestid, streamid, streamflags, frametype, frameflags, payload = fields
183 requestid, streamid, streamflags, frametype, frameflags, payload = fields
@@ -196,7 +205,11 b' def makeframefromhumanstring(s):'
196 else:
205 else:
197 finalflags |= int(flag)
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 return makeframe(requestid=requestid, streamid=streamid,
214 return makeframe(requestid=requestid, streamid=streamid,
202 streamflags=finalstreamflags, typeid=frametype,
215 streamflags=finalstreamflags, typeid=frametype,
@@ -35,6 +35,59 b' def sendcommandframes(reactor, stream, r'
35 framing.createcommandframes(stream, rid, cmd, args,
35 framing.createcommandframes(stream, rid, cmd, args,
36 datafh))
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 class FrameTests(unittest.TestCase):
91 class FrameTests(unittest.TestCase):
39 def testdataexactframesize(self):
92 def testdataexactframesize(self):
40 data = util.bytesio(b'x' * framing.DEFAULT_MAX_FRAME_SIZE)
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