# HG changeset patch # User Gregory Szorc # Date 1523731746 25200 # Node ID f7673845b167886277e21a8b0dbac9826b042921 # Parent d715a85003c8327b1936900a2c055483721530a8 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 diff -r d715a85003c8 -r f7673845b167 mercurial/wireprotov2peer.py --- 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, +} diff -r d715a85003c8 -r f7673845b167 tests/test-wireproto-command-branchmap.t --- 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 diff -r d715a85003c8 -r f7673845b167 tests/test-wireproto-command-heads.t --- 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 diff -r d715a85003c8 -r f7673845b167 tests/test-wireproto-command-known.t --- 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 diff -r d715a85003c8 -r f7673845b167 tests/test-wireproto-command-listkeys.t --- 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 diff -r d715a85003c8 -r f7673845b167 tests/test-wireproto-command-lookup.t --- 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 diff -r d715a85003c8 -r f7673845b167 tests/test-wireproto-command-pushkey.t --- 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