wireprotov2: decode responses to their expected types
Callers of established wire protocol commands expect the
response from that command to be decoded into a data structure.
It's not very useful if callers get back a stream of bytes and
don't know how they should be interpreted - especially since that
stream of bytes varies by wire protocol and even the transport
within that protocol version.
This commit establishes decoding functions for various command
responses so callers of those commands get the response type
they expect.
In theory, this should make the version 2 HTTP peer usable for
various operations. But I haven't tested to confirm.
Differential Revision: https://phab.mercurial-scm.org/D3381
--- a/mercurial/wireprotov2peer.py Sat Apr 14 11:46:08 2018 -0700
+++ b/mercurial/wireprotov2peer.py Sat Apr 14 11:49:06 2018 -0700
@@ -12,6 +12,7 @@
cbor,
)
from . import (
+ encoding,
error,
util,
wireprotoframing,
@@ -127,7 +128,13 @@
response.cbor = True
if meta['eos']:
- self._futures[frame.requestid].set_result(response)
+ # If the command has a decoder, resolve the future to the
+ # decoded value. Otherwise resolve to the rich response object.
+ decoder = COMMAND_DECODERS.get(response.command)
+
+ result = decoder(response) if decoder else response
+
+ self._futures[frame.requestid].set_result(result)
del self._requests[frame.requestid]
del self._futures[frame.requestid]
@@ -135,3 +142,38 @@
else:
raise error.ProgrammingError(
'unhandled action from clientreactor: %s' % action)
+
+def decodebranchmap(resp):
+ # Response should be a single CBOR map of branch name to array of nodes.
+ bm = next(resp.cborobjects())
+
+ return {encoding.tolocal(k): v for k, v in bm.items()}
+
+def decodeheads(resp):
+ # Array of node bytestrings.
+ return next(resp.cborobjects())
+
+def decodeknown(resp):
+ # Bytestring where each byte is a 0 or 1.
+ raw = next(resp.cborobjects())
+
+ return [True if c == '1' else False for c in raw]
+
+def decodelistkeys(resp):
+ # Map with bytestring keys and values.
+ return next(resp.cborobjects())
+
+def decodelookup(resp):
+ return next(resp.cborobjects())
+
+def decodepushkey(resp):
+ return next(resp.cborobjects())
+
+COMMAND_DECODERS = {
+ 'branchmap': decodebranchmap,
+ 'heads': decodeheads,
+ 'known': decodeknown,
+ 'listkeys': decodelistkeys,
+ 'lookup': decodelookup,
+ 'pushkey': decodepushkey,
+}
--- a/tests/test-wireproto-command-branchmap.t Sat Apr 14 11:46:08 2018 -0700
+++ b/tests/test-wireproto-command-branchmap.t Sat Apr 14 11:49:06 2018 -0700
@@ -67,6 +67,6 @@
received frame(size=112; request=1; stream=2; streamflags=stream-begin; type=bytes-response; flags=eos|cbor)
s> 0\r\n
s> \r\n
- response: [{b'branch1': [b'\xb5\xfa\xac\xdf\xd2c7h\xcb1R3l\xc0\x953\x81&f\x88'], b'branch2': [b'"Aa\xc7X\x9a\xa4\x8f\xa8:H\xfe\xff^\x95\xb5j\xe3\'\xfc'], b'default': [b'&\x80Z\xba\x1e`\n\x82\xe96a\x14\x9f#\x13\x86j"\x1a{', b'\xbe\x0e\xf7<\x17\xad\xe3\xfc\x89\xdcAp\x1e\xb9\xfc:\x91\xb5\x82\x82']}]
+ response: {b'branch1': [b'\xb5\xfa\xac\xdf\xd2c7h\xcb1R3l\xc0\x953\x81&f\x88'], b'branch2': [b'"Aa\xc7X\x9a\xa4\x8f\xa8:H\xfe\xff^\x95\xb5j\xe3\'\xfc'], b'default': [b'&\x80Z\xba\x1e`\n\x82\xe96a\x14\x9f#\x13\x86j"\x1a{', b'\xbe\x0e\xf7<\x17\xad\xe3\xfc\x89\xdcAp\x1e\xb9\xfc:\x91\xb5\x82\x82']}
$ cat error.log
--- a/tests/test-wireproto-command-heads.t Sat Apr 14 11:46:08 2018 -0700
+++ b/tests/test-wireproto-command-heads.t Sat Apr 14 11:49:06 2018 -0700
@@ -58,7 +58,7 @@
received frame(size=64; request=1; stream=2; streamflags=stream-begin; type=bytes-response; flags=eos|cbor)
s> 0\r\n
s> \r\n
- response: [[b'\x1dok\x91\xd4J\xab\xa6\xd5\xe5\x80\xbc0\xa9\x94\x850\xdb\xe0\x0b', b'\xaeI.6\xb0\xc83\x9f\xfa\xf3(\xd0\x0b\x85\xb4R]\xe1\x16^', b')Dm-\xc5A\x9c_\x97Dz\x8b\xc0b\xe4\xcc2\x8b\xf2A']]
+ response: [b'\x1dok\x91\xd4J\xab\xa6\xd5\xe5\x80\xbc0\xa9\x94\x850\xdb\xe0\x0b', b'\xaeI.6\xb0\xc83\x9f\xfa\xf3(\xd0\x0b\x85\xb4R]\xe1\x16^', b')Dm-\xc5A\x9c_\x97Dz\x8b\xc0b\xe4\xcc2\x8b\xf2A']
Requesting just the public heads works
@@ -91,6 +91,6 @@
received frame(size=22; request=1; stream=2; streamflags=stream-begin; type=bytes-response; flags=eos|cbor)
s> 0\r\n
s> \r\n
- response: [[b'x\xd2\xdc\xa46\xb2\xf5\xb1\x88\xac&~)\xb8\x1e\x07&m8\xfc']]
+ response: [b'x\xd2\xdc\xa46\xb2\xf5\xb1\x88\xac&~)\xb8\x1e\x07&m8\xfc']
$ cat error.log
--- a/tests/test-wireproto-command-known.t Sat Apr 14 11:46:08 2018 -0700
+++ b/tests/test-wireproto-command-known.t Sat Apr 14 11:49:06 2018 -0700
@@ -50,7 +50,7 @@
received frame(size=1; request=1; stream=2; streamflags=stream-begin; type=bytes-response; flags=eos|cbor)
s> 0\r\n
s> \r\n
- response: [b'']
+ response: []
Single known node works
@@ -83,7 +83,7 @@
received frame(size=2; request=1; stream=2; streamflags=stream-begin; type=bytes-response; flags=eos|cbor)
s> 0\r\n
s> \r\n
- response: [b'1']
+ response: [True]
Multiple nodes works
@@ -116,6 +116,6 @@
received frame(size=4; request=1; stream=2; streamflags=stream-begin; type=bytes-response; flags=eos|cbor)
s> 0\r\n
s> \r\n
- response: [b'101']
+ response: [True, False, True]
$ cat error.log
--- a/tests/test-wireproto-command-listkeys.t Sat Apr 14 11:46:08 2018 -0700
+++ b/tests/test-wireproto-command-listkeys.t Sat Apr 14 11:49:06 2018 -0700
@@ -54,7 +54,7 @@
received frame(size=32; request=1; stream=2; streamflags=stream-begin; type=bytes-response; flags=eos|cbor)
s> 0\r\n
s> \r\n
- response: [{b'bookmarks': b'', b'namespaces': b'', b'phases': b''}]
+ response: {b'bookmarks': b'', b'namespaces': b'', b'phases': b''}
Request for phases works
@@ -87,7 +87,7 @@
received frame(size=61; request=1; stream=2; streamflags=stream-begin; type=bytes-response; flags=eos|cbor)
s> 0\r\n
s> \r\n
- response: [{b'be0ef73c17ade3fc89dc41701eb9fc3a91b58282': b'1', b'publishing': b'True'}]
+ response: {b'be0ef73c17ade3fc89dc41701eb9fc3a91b58282': b'1', b'publishing': b'True'}
Request for bookmarks works
@@ -120,6 +120,6 @@
received frame(size=45; request=1; stream=2; streamflags=stream-begin; type=bytes-response; flags=eos|cbor)
s> 0\r\n
s> \r\n
- response: [{b'@': b'26805aba1e600a82e93661149f2313866a221a7b'}]
+ response: {b'@': b'26805aba1e600a82e93661149f2313866a221a7b'}
$ cat error.log
--- a/tests/test-wireproto-command-lookup.t Sat Apr 14 11:46:08 2018 -0700
+++ b/tests/test-wireproto-command-lookup.t Sat Apr 14 11:49:06 2018 -0700
@@ -50,6 +50,6 @@
received frame(size=*; request=1; stream=2; streamflags=stream-begin; type=bytes-response; flags=eos|cbor) (glob)
s> 0\r\n
s> \r\n
- response: [b'Bk\xad\xa5\xc6u\x98\xcae\x03mW\xd9\xe4\xb6K\x0c\x1c\xe7\xa0']
+ response: b'Bk\xad\xa5\xc6u\x98\xcae\x03mW\xd9\xe4\xb6K\x0c\x1c\xe7\xa0'
$ cat error.log
--- a/tests/test-wireproto-command-pushkey.t Sat Apr 14 11:46:08 2018 -0700
+++ b/tests/test-wireproto-command-pushkey.t Sat Apr 14 11:49:06 2018 -0700
@@ -53,7 +53,7 @@
received frame(size=*; request=1; stream=2; streamflags=stream-begin; type=bytes-response; flags=eos|cbor) (glob)
s> 0\r\n
s> \r\n
- response: [True]
+ response: True
$ sendhttpv2peer << EOF
> command listkeys
@@ -84,6 +84,6 @@
received frame(size=45; request=1; stream=2; streamflags=stream-begin; type=bytes-response; flags=eos|cbor)
s> 0\r\n
s> \r\n
- response: [{b'@': b'426bada5c67598ca65036d57d9e4b64b0c1ce7a0'}]
+ response: {b'@': b'426bada5c67598ca65036d57d9e4b64b0c1ce7a0'}
$ cat error.log