diff --git a/mercurial/debugcommands.py b/mercurial/debugcommands.py --- a/mercurial/debugcommands.py +++ b/mercurial/debugcommands.py @@ -17,6 +17,7 @@ import socket import ssl import string +import subprocess import sys import tempfile import time @@ -65,6 +66,7 @@ setdiscovery, simplemerge, smartset, + sshpeer, sslutil, streamclone, templater, @@ -2528,3 +2530,204 @@ ui.write("%s\n" % res1) if res1 != res2: ui.warn("%s\n" % res2) + +def _parsewirelangblocks(fh): + activeaction = None + blocklines = [] + + for line in fh: + line = line.rstrip() + if not line: + continue + + if line.startswith(b'#'): + continue + + if not line.startswith(' '): + # New block. Flush previous one. + if activeaction: + yield activeaction, blocklines + + activeaction = line + blocklines = [] + continue + + # Else we start with an indent. + + if not activeaction: + raise error.Abort(_('indented line outside of block')) + + blocklines.append(line) + + # Flush last block. + if activeaction: + yield activeaction, blocklines + +@command('debugwireproto', + [ + ('', 'localssh', False, _('start an SSH server for this repo')), + ('', 'peer', '', _('construct a specific version of the peer')), + ] + cmdutil.remoteopts, + _('[REPO]'), + optionalrepo=True) +def debugwireproto(ui, repo, **opts): + """send wire protocol commands to a server + + This command can be used to issue wire protocol commands to remote + peers and to debug the raw data being exchanged. + + ``--localssh`` will start an SSH server against the current repository + and connect to that. By default, the connection will perform a handshake + and establish an appropriate peer instance. + + ``--peer`` can be used to bypass the handshake protocol and construct a + peer instance using the specified class type. Valid values are ``raw``, + ``ssh1``, and ``ssh2``. ``raw`` instances only allow sending raw data + payloads and don't support higher-level command actions. + + Commands are issued via a mini language which is specified via stdin. + The language consists of individual actions to perform. An action is + defined by a block. A block is defined as a line with no leading + space followed by 0 or more lines with leading space. Blocks are + effectively a high-level command with additional metadata. + + Lines beginning with ``#`` are ignored. + + The following sections denote available actions. + + raw + --- + + Send raw data to the server. + + The block payload contains the raw data to send as one atomic send + operation. The data may not actually be delivered in a single system + call: it depends on the abilities of the transport being used. + + Each line in the block is de-indented and concatenated. Then, that + value is evaluated as a Python b'' literal. This allows the use of + backslash escaping, etc. + + raw+ + ---- + + Behaves like ``raw`` except flushes output afterwards. + + close + ----- + + Close the connection to the server. + + flush + ----- + + Flush data written to the server. + + readavailable + ------------- + + Read all available data from the server. + + If the connection to the server encompasses multiple pipes, we poll both + pipes and read available data. + + readline + -------- + + Read a line of output from the server. If there are multiple output + pipes, reads only the main pipe. + """ + opts = pycompat.byteskwargs(opts) + + if opts['localssh'] and not repo: + raise error.Abort(_('--localssh requires a repository')) + + if opts['peer'] and opts['peer'] not in ('raw', 'ssh1', 'ssh2'): + raise error.Abort(_('invalid value for --peer'), + hint=_('valid values are "raw", "ssh1", and "ssh2"')) + + if ui.interactive(): + ui.write(_('(waiting for commands on stdin)\n')) + + blocks = list(_parsewirelangblocks(ui.fin)) + + proc = None + + if opts['localssh']: + # We start the SSH server in its own process so there is process + # separation. This prevents a whole class of potential bugs around + # shared state from interfering with server operation. + args = util.hgcmd() + [ + '-R', repo.root, + 'debugserve', '--sshstdio', + ] + proc = subprocess.Popen(args, stdin=subprocess.PIPE, + stdout=subprocess.PIPE, stderr=subprocess.PIPE, + bufsize=0) + + stdin = proc.stdin + stdout = proc.stdout + stderr = proc.stderr + + # We turn the pipes into observers so we can log I/O. + if ui.verbose or opts['peer'] == 'raw': + stdin = util.makeloggingfileobject(ui, proc.stdin, b'i', + logdata=True) + stdout = util.makeloggingfileobject(ui, proc.stdout, b'o', + logdata=True) + stderr = util.makeloggingfileobject(ui, proc.stderr, b'e', + logdata=True) + + # --localssh also implies the peer connection settings. + + url = 'ssh://localserver' + + if opts['peer'] == 'ssh1': + ui.write(_('creating ssh peer for wire protocol version 1\n')) + peer = sshpeer.sshv1peer(ui, url, proc, stdin, stdout, stderr, + None) + elif opts['peer'] == 'ssh2': + ui.write(_('creating ssh peer for wire protocol version 2\n')) + peer = sshpeer.sshv2peer(ui, url, proc, stdin, stdout, stderr, + None) + elif opts['peer'] == 'raw': + ui.write(_('using raw connection to peer\n')) + peer = None + else: + ui.write(_('creating ssh peer from handshake results\n')) + peer = sshpeer.makepeer(ui, url, proc, stdin, stdout, stderr) + + else: + raise error.Abort(_('only --localssh is currently supported')) + + # Now perform actions based on the parsed wire language instructions. + for action, lines in blocks: + if action in ('raw', 'raw+'): + # Concatenate the data together. + data = ''.join(l.lstrip() for l in lines) + data = util.unescapestr(data) + stdin.write(data) + + if action == 'raw+': + stdin.flush() + elif action == 'flush': + stdin.flush() + elif action == 'close': + peer.close() + elif action == 'readavailable': + fds = util.poll([stdout.fileno(), stderr.fileno()]) + + if stdout.fileno() in fds: + util.readpipe(stdout) + if stderr.fileno() in fds: + util.readpipe(stderr) + elif action == 'readline': + stdout.readline() + else: + raise error.Abort(_('unknown action: %s') % action) + + if peer: + peer.close() + + if proc: + proc.kill() diff --git a/tests/test-completion.t b/tests/test-completion.t --- a/tests/test-completion.t +++ b/tests/test-completion.t @@ -121,6 +121,7 @@ debugupgraderepo debugwalk debugwireargs + debugwireproto Do not show the alias of a debug command if there are other candidates (this should hide rawcommit) @@ -302,6 +303,7 @@ debugupgraderepo: optimize, run debugwalk: include, exclude debugwireargs: three, four, five, ssh, remotecmd, insecure + debugwireproto: localssh, peer, ssh, remotecmd, insecure files: rev, print0, include, exclude, template, subrepos graft: rev, continue, edit, log, force, currentdate, currentuser, date, user, tool, dry-run grep: print0, all, text, follow, ignore-case, files-with-matches, line-number, rev, user, date, template, include, exclude diff --git a/tests/test-help.t b/tests/test-help.t --- a/tests/test-help.t +++ b/tests/test-help.t @@ -983,6 +983,8 @@ debugwalk show how files match on given patterns debugwireargs (no help text available) + debugwireproto + send wire protocol commands to a server (use 'hg help -v debug' to show built-in aliases and global options) diff --git a/tests/test-ssh-proto.t b/tests/test-ssh-proto.t --- a/tests/test-ssh-proto.t +++ b/tests/test-ssh-proto.t @@ -12,10 +12,29 @@ $ echo 0 > foo $ hg -q add foo $ hg commit -m initial - $ cd .. + +A no-op connection performs a handshake + + $ hg debugwireproto --localssh << EOF + > EOF + creating ssh peer from handshake results + +Raw peers don't perform any activity + + $ hg debugwireproto --localssh --peer raw << EOF + > EOF + using raw connection to peer + $ hg debugwireproto --localssh --peer ssh1 << EOF + > EOF + creating ssh peer for wire protocol version 1 + $ hg debugwireproto --localssh --peer ssh2 << EOF + > EOF + creating ssh peer for wire protocol version 2 Test a normal behaving server, for sanity + $ cd .. + $ hg --debug debugpeer ssh://user@dummy/server running * "*/tests/dummyssh" 'user@dummy' 'hg -R server serve --stdio' (glob) (no-windows !) running * "*\tests/dummyssh" "user@dummy" "hg -R server serve --stdio" (glob) (windows !) @@ -33,11 +52,19 @@ Server should answer the "hello" command in isolation - $ hg -R server serve --stdio << EOF - > hello + $ hg -R server debugwireproto --localssh --peer raw << EOF + > raw + > hello\n + > readline + > readline > EOF - 384 - capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN + using raw connection to peer + i> write(6) -> None: + i> hello\n + o> readline() -> 4: + o> 384\n + o> readline() -> 384: + o> capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN\n `hg debugserve --sshstdio` works @@ -80,16 +107,33 @@ Server should reply with capabilities and should send "1\n\n" as a successful reply with empty response to the "between". - $ hg -R server serve --stdio << EOF - > hello - > between - > pairs 81 - > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 + $ hg -R server debugwireproto --localssh --peer raw << EOF + > raw + > hello\n + > readline + > readline + > raw + > between\n + > pairs 81\n + > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 + > readline + > readline > EOF - 384 - capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN - 1 - + using raw connection to peer + i> write(6) -> None: + i> hello\n + o> readline() -> 4: + o> 384\n + o> readline() -> 384: + o> capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN\n + i> write(98) -> None: + i> between\n + i> pairs 81\n + i> 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 + o> readline() -> 2: + o> 1\n + o> readline() -> 1: + o> \n SSH banner is not printed by default, ignored by clients @@ -127,26 +171,63 @@ And test the banner with the raw protocol - $ SSHSERVERMODE=banner hg -R server serve --stdio << EOF - > hello - > between - > pairs 81 - > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 + $ SSHSERVERMODE=banner hg -R server debugwireproto --localssh --peer raw << EOF + > raw + > hello\n + > readline + > readline + > readline + > readline + > readline + > readline + > readline + > readline + > readline + > readline + > readline + > readline + > raw + > between\n + > pairs 81\n + > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 + > readline + > readline > EOF - banner: line 0 - banner: line 1 - banner: line 2 - banner: line 3 - banner: line 4 - banner: line 5 - banner: line 6 - banner: line 7 - banner: line 8 - banner: line 9 - 384 - capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN - 1 - + using raw connection to peer + i> write(6) -> None: + i> hello\n + o> readline() -> 15: + o> banner: line 0\n + o> readline() -> 15: + o> banner: line 1\n + o> readline() -> 15: + o> banner: line 2\n + o> readline() -> 15: + o> banner: line 3\n + o> readline() -> 15: + o> banner: line 4\n + o> readline() -> 15: + o> banner: line 5\n + o> readline() -> 15: + o> banner: line 6\n + o> readline() -> 15: + o> banner: line 7\n + o> readline() -> 15: + o> banner: line 8\n + o> readline() -> 15: + o> banner: line 9\n + o> readline() -> 4: + o> 384\n + o> readline() -> 384: + o> capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN\n + i> write(98) -> None: + i> between\n + i> pairs 81\n + i> 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 + o> readline() -> 2: + o> 1\n + o> readline() -> 1: + o> \n Connecting to a <0.9.1 server that doesn't support the hello command. The client should refuse, as we dropped support for connecting to such @@ -167,18 +248,37 @@ Sending an unknown command to the server results in an empty response to that command - $ hg -R server serve --stdio << EOF - > pre-hello - > hello - > between - > pairs 81 - > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 + $ hg -R server debugwireproto --localssh --peer raw << EOF + > raw + > pre-hello\n + > readline + > raw + > hello\n + > readline + > raw + > between\n + > pairs 81\n + > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 + > readline + > readline > EOF - 0 - 384 - capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN - 1 - + using raw connection to peer + i> write(10) -> None: + i> pre-hello\n + o> readline() -> 2: + o> 0\n + i> write(6) -> None: + i> hello\n + o> readline() -> 4: + o> 384\n + i> write(98) -> None: + i> between\n + i> pairs 81\n + i> 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 + o> readline() -> 384: + o> capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN\n + o> readline() -> 2: + o> 1\n $ hg --config sshpeer.mode=extra-handshake-commands --config sshpeer.handshake-mode=pre-no-args --debug debugpeer ssh://user@dummy/server running * "*/tests/dummyssh" 'user@dummy' 'hg -R server serve --stdio' (glob) (no-windows !) @@ -199,22 +299,54 @@ Send multiple unknown commands before hello - $ hg -R server serve --stdio << EOF - > unknown1 - > unknown2 - > unknown3 - > hello - > between - > pairs 81 - > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 + $ hg -R server debugwireproto --localssh --peer raw << EOF + > raw + > unknown1\n + > readline + > raw + > unknown2\n + > readline + > raw + > unknown3\n + > readline + > raw + > hello\n + > readline + > readline + > raw + > between\n + > pairs 81\n + > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 + > readline + > readline > EOF - 0 - 0 - 0 - 384 - capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN - 1 - + using raw connection to peer + i> write(9) -> None: + i> unknown1\n + o> readline() -> 2: + o> 0\n + i> write(9) -> None: + i> unknown2\n + o> readline() -> 2: + o> 0\n + i> write(9) -> None: + i> unknown3\n + o> readline() -> 2: + o> 0\n + i> write(6) -> None: + i> hello\n + o> readline() -> 4: + o> 384\n + o> readline() -> 384: + o> capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN\n + i> write(98) -> None: + i> between\n + i> pairs 81\n + i> 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 + o> readline() -> 2: + o> 1\n + o> readline() -> 1: + o> \n $ hg --config sshpeer.mode=extra-handshake-commands --config sshpeer.handshake-mode=pre-multiple-no-args --debug debugpeer ssh://user@dummy/server running * "*/tests/dummyssh" 'user@dummy' 'hg -R server serve --stdio' (glob) (no-windows !) @@ -239,62 +371,154 @@ Send an unknown command before hello that has arguments - $ hg -R server serve --stdio << EOF - > with-args - > foo 13 - > value for foo - > bar 13 - > value for bar - > hello - > between - > pairs 81 - > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 + $ cd server + + $ hg debugwireproto --localssh --peer raw << EOF + > raw + > with-args\n + > foo 13\n + > value for foo\n + > bar 13\n + > value for bar\n + > readline + > readline + > readline + > readline + > readline + > raw + > hello\n + > readline + > readline + > raw + > between\n + > pairs 81\n + > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 + > readline + > readline > EOF - 0 - 0 - 0 - 0 - 0 - 384 - capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN - 1 - + using raw connection to peer + i> write(52) -> None: + i> with-args\n + i> foo 13\n + i> value for foo\n + i> bar 13\n + i> value for bar\n + o> readline() -> 2: + o> 0\n + o> readline() -> 2: + o> 0\n + o> readline() -> 2: + o> 0\n + o> readline() -> 2: + o> 0\n + o> readline() -> 2: + o> 0\n + i> write(6) -> None: + i> hello\n + o> readline() -> 4: + o> 384\n + o> readline() -> 384: + o> capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN\n + i> write(98) -> None: + i> between\n + i> pairs 81\n + i> 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 + o> readline() -> 2: + o> 1\n + o> readline() -> 1: + o> \n Send an unknown command having an argument that looks numeric - $ hg -R server serve --stdio << EOF - > unknown - > foo 1 - > 0 - > hello - > between - > pairs 81 - > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 + $ hg debugwireproto --localssh --peer raw << EOF + > raw + > unknown\n + > foo 1\n + > 0\n + > readline + > readline + > readline + > raw + > hello\n + > readline + > readline + > raw + > between\n + > pairs 81\n + > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 + > readline + > readline > EOF - 0 - 0 - 0 - 384 - capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN - 1 - + using raw connection to peer + i> write(16) -> None: + i> unknown\n + i> foo 1\n + i> 0\n + o> readline() -> 2: + o> 0\n + o> readline() -> 2: + o> 0\n + o> readline() -> 2: + o> 0\n + i> write(6) -> None: + i> hello\n + o> readline() -> 4: + o> 384\n + o> readline() -> 384: + o> capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN\n + i> write(98) -> None: + i> between\n + i> pairs 81\n + i> 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 + o> readline() -> 2: + o> 1\n + o> readline() -> 1: + o> \n - $ hg -R server serve --stdio << EOF - > unknown - > foo 1 - > 1 - > hello - > between - > pairs 81 - > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 + $ hg debugwireproto --localssh --peer raw << EOF + > raw + > unknown\n + > foo 1\n + > 1\n + > readline + > readline + > readline + > raw + > hello\n + > readline + > readline + > raw + > between\n + > pairs 81\n + > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 + > readline + > readline > EOF - 0 - 0 - 0 - 384 - capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN - 1 - + using raw connection to peer + i> write(16) -> None: + i> unknown\n + i> foo 1\n + i> 1\n + o> readline() -> 2: + o> 0\n + o> readline() -> 2: + o> 0\n + o> readline() -> 2: + o> 0\n + i> write(6) -> None: + i> hello\n + o> readline() -> 4: + o> 384\n + o> readline() -> 384: + o> capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN\n + i> write(98) -> None: + i> between\n + i> pairs 81\n + i> 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 + o> readline() -> 2: + o> 1\n + o> readline() -> 1: + o> \n When sending a dict argument value, it is serialized to " " followed by " \n" for each item @@ -302,176 +526,402 @@ Dictionary value for unknown command - $ hg -R server serve --stdio << EOF - > unknown - > dict 3 - > key1 3 - > foo - > key2 3 - > bar - > key3 3 - > baz - > hello + $ hg debugwireproto --localssh --peer raw << EOF + > raw + > unknown\n + > dict 3\n + > key1 3\n + > foo\n + > key2 3\n + > bar\n + > key3 3\n + > baz\n + > readline + > readline + > readline + > readline + > readline + > readline + > readline + > readline + > raw + > hello\n + > readline + > readline > EOF - 0 - 0 - 0 - 0 - 0 - 0 - 0 - 0 - 384 - capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN + using raw connection to peer + i> write(48) -> None: + i> unknown\n + i> dict 3\n + i> key1 3\n + i> foo\n + i> key2 3\n + i> bar\n + i> key3 3\n + i> baz\n + o> readline() -> 2: + o> 0\n + o> readline() -> 2: + o> 0\n + o> readline() -> 2: + o> 0\n + o> readline() -> 2: + o> 0\n + o> readline() -> 2: + o> 0\n + o> readline() -> 2: + o> 0\n + o> readline() -> 2: + o> 0\n + o> readline() -> 2: + o> 0\n + i> write(6) -> None: + i> hello\n + o> readline() -> 4: + o> 384\n + o> readline() -> 384: + o> capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN\n Incomplete dictionary send - $ hg -R server serve --stdio << EOF - > unknown - > dict 3 - > key1 3 - > foo + $ hg debugwireproto --localssh --peer raw << EOF + > raw + > unknown\n + > dict 3\n + > key1 3\n + > foo\n + > readline + > readline + > readline + > readline > EOF - 0 - 0 - 0 - 0 + using raw connection to peer + i> write(26) -> None: + i> unknown\n + i> dict 3\n + i> key1 3\n + i> foo\n + o> readline() -> 2: + o> 0\n + o> readline() -> 2: + o> 0\n + o> readline() -> 2: + o> 0\n + o> readline() -> 2: + o> 0\n Incomplete value send - $ hg -R server serve --stdio << EOF - > unknown - > dict 3 - > key1 3 - > fo + $ hg debugwireproto --localssh --peer raw << EOF + > raw + > unknown\n + > dict 3\n + > key1 3\n + > fo + > readline + > readline + > readline > EOF - 0 - 0 - 0 - 0 + using raw connection to peer + i> write(24) -> None: + i> unknown\n + i> dict 3\n + i> key1 3\n + i> fo + o> readline() -> 2: + o> 0\n + o> readline() -> 2: + o> 0\n + o> readline() -> 2: + o> 0\n Send a command line with spaces - $ hg -R server serve --stdio << EOF - > unknown withspace - > hello - > between - > pairs 81 - > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 + $ hg debugwireproto --localssh --peer raw << EOF + > raw + > unknown withspace\n + > readline + > raw + > hello\n + > readline + > readline + > raw + > between\n + > pairs 81\n + > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 + > readline + > readline > EOF - 0 - 384 - capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN - 1 - + using raw connection to peer + i> write(18) -> None: + i> unknown withspace\n + o> readline() -> 2: + o> 0\n + i> write(6) -> None: + i> hello\n + o> readline() -> 4: + o> 384\n + o> readline() -> 384: + o> capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN\n + i> write(98) -> None: + i> between\n + i> pairs 81\n + i> 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 + o> readline() -> 2: + o> 1\n + o> readline() -> 1: + o> \n - $ hg -R server serve --stdio << EOF - > unknown with multiple spaces - > hello - > between - > pairs 81 - > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 + $ hg debugwireproto --localssh --peer raw << EOF + > raw + > unknown with multiple spaces\n + > readline + > raw + > hello\n + > readline + > readline + > raw + > between\n + > pairs 81\n + > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 + > readline > EOF - 0 - 384 - capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN - 1 - + using raw connection to peer + i> write(29) -> None: + i> unknown with multiple spaces\n + o> readline() -> 2: + o> 0\n + i> write(6) -> None: + i> hello\n + o> readline() -> 4: + o> 384\n + o> readline() -> 384: + o> capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN\n + i> write(98) -> None: + i> between\n + i> pairs 81\n + i> 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 + o> readline() -> 2: + o> 1\n - $ hg -R server serve --stdio << EOF - > unknown with spaces - > key 10 - > some value - > hello - > between - > pairs 81 - > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 + $ hg debugwireproto --localssh --peer raw << EOF + > raw + > unknown with spaces\n + > key 10\n + > some value\n + > readline + > readline + > readline + > raw + > hello\n + > readline + > readline + > raw + > between\n + > pairs 81\n + > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 + > readline + > readline > EOF - 0 - 0 - 0 - 384 - capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN - 1 - + using raw connection to peer + i> write(38) -> None: + i> unknown with spaces\n + i> key 10\n + i> some value\n + o> readline() -> 2: + o> 0\n + o> readline() -> 2: + o> 0\n + o> readline() -> 2: + o> 0\n + i> write(6) -> None: + i> hello\n + o> readline() -> 4: + o> 384\n + o> readline() -> 384: + o> capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN\n + i> write(98) -> None: + i> between\n + i> pairs 81\n + i> 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 + o> readline() -> 2: + o> 1\n + o> readline() -> 1: + o> \n Send an unknown command after the "between" - $ hg -R server serve --stdio << EOF - > hello - > between - > pairs 81 - > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000unknown + $ hg debugwireproto --localssh --peer raw << EOF + > raw + > hello\n + > readline + > readline + > raw + > between\n + > pairs 81\n + > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000unknown + > readline + > readline > EOF - 384 - capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN - 1 - - 0 + using raw connection to peer + i> write(6) -> None: + i> hello\n + o> readline() -> 4: + o> 384\n + o> readline() -> 384: + o> capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN\n + i> write(105) -> None: + i> between\n + i> pairs 81\n + i> 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000unknown + o> readline() -> 2: + o> 1\n + o> readline() -> 1: + o> \n And one with arguments - $ hg -R server serve --stdio << EOF - > hello - > between - > pairs 81 - > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000unknown - > foo 5 - > value - > bar 3 - > baz + $ hg debugwireproto --localssh --peer raw << EOF + > raw + > hello\n + > between\n + > pairs 81\n + > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 + > readline + > readline + > readline + > readline + > raw + > unknown\n + > foo 5\n + > \nvalue\n + > bar 3\n + > baz\n + > readline + > readline + > readline > EOF - 384 - capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN - 1 - - 0 - 0 - 0 - 0 - 0 + using raw connection to peer + i> write(104) -> None: + i> hello\n + i> between\n + i> pairs 81\n + i> 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 + o> readline() -> 4: + o> 384\n + o> readline() -> 384: + o> capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN\n + o> readline() -> 2: + o> 1\n + o> readline() -> 1: + o> \n + i> write(31) -> None: + i> unknown\n + i> foo 5\n + i> \n + i> value\n + i> bar 3\n + i> baz\n + o> readline() -> 2: + o> 0\n + o> readline() -> 2: + o> 0\n + o> readline() -> 0: Send a valid command before the handshake - $ hg -R server serve --stdio << EOF - > heads - > hello - > between - > pairs 81 - > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 + $ hg debugwireproto --localssh --peer raw << EOF + > raw + > heads\n + > readline + > raw + > hello\n + > between\n + > pairs 81\n + > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 + > readline + > readline + > readline + > readline > EOF - 41 - 68986213bd4485ea51533535e3fc9e78007a711f - 384 - capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN - 1 - + using raw connection to peer + i> write(6) -> None: + i> heads\n + o> readline() -> 3: + o> 41\n + i> write(104) -> None: + i> hello\n + i> between\n + i> pairs 81\n + i> 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 + o> readline() -> 41: + o> 68986213bd4485ea51533535e3fc9e78007a711f\n + o> readline() -> 4: + o> 384\n + o> readline() -> 384: + o> capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN\n + o> readline() -> 2: + o> 1\n And a variation that doesn't send the between command - $ hg -R server serve --stdio << EOF - > heads - > hello + $ hg debugwireproto --localssh --peer raw << EOF + > raw + > heads\n + > readline + > raw + > hello\n + > readline + > readline > EOF - 41 - 68986213bd4485ea51533535e3fc9e78007a711f - 384 - capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN + using raw connection to peer + i> write(6) -> None: + i> heads\n + o> readline() -> 3: + o> 41\n + i> write(6) -> None: + i> hello\n + o> readline() -> 41: + o> 68986213bd4485ea51533535e3fc9e78007a711f\n + o> readline() -> 4: + o> 384\n Send an upgrade request to a server that doesn't support that command - $ hg -R server serve --stdio << EOF - > upgrade 2e82ab3f-9ce3-4b4e-8f8c-6fd1c0e9e23a proto=irrelevant1%2Cirrelevant2 - > hello - > between - > pairs 81 - > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 + $ hg debugwireproto --localssh --peer raw << EOF + > raw + > upgrade 2e82ab3f-9ce3-4b4e-8f8c-6fd1c0e9e23a proto=irrelevant1%2Cirrelevant2\n + > readline + > raw + > hello\n + > between\n + > pairs 81\n + > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 + > readline + > readline + > readline + > readline > EOF - 0 - 384 - capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN - 1 - + using raw connection to peer + i> write(77) -> None: + i> upgrade 2e82ab3f-9ce3-4b4e-8f8c-6fd1c0e9e23a proto=irrelevant1%2Cirrelevant2\n + o> readline() -> 2: + o> 0\n + i> write(104) -> None: + i> hello\n + i> between\n + i> pairs 81\n + i> 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 + o> readline() -> 4: + o> 384\n + o> readline() -> 384: + o> capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN\n + o> readline() -> 2: + o> 1\n + o> readline() -> 1: + o> \n + + $ cd .. $ hg --config experimental.sshpeer.advertise-v2=true --debug debugpeer ssh://user@dummy/server running * "*/tests/dummyssh" 'user@dummy' 'hg -R server serve --stdio' (glob) (no-windows !) @@ -500,17 +950,34 @@ Send an upgrade request to a server that supports upgrade - >>> with open('payload', 'wb') as fh: - ... fh.write(b'upgrade this-is-some-token proto=exp-ssh-v2-0001\n') - ... fh.write(b'hello\n') - ... fh.write(b'between\n') - ... fh.write(b'pairs 81\n') - ... fh.write(b'0000000000000000000000000000000000000000-0000000000000000000000000000000000000000') + $ cd server - $ hg -R server serve --stdio < payload - upgraded this-is-some-token exp-ssh-v2-0001 - 383 - capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN + $ hg debugwireproto --localssh --peer raw << EOF + > raw + > upgrade this-is-some-token proto=exp-ssh-v2-0001\n + > hello\n + > between\n + > pairs 81\n + > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 + > readline + > readline + > readline + > EOF + using raw connection to peer + i> write(153) -> None: + i> upgrade this-is-some-token proto=exp-ssh-v2-0001\n + i> hello\n + i> between\n + i> pairs 81\n + i> 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 + o> readline() -> 44: + o> upgraded this-is-some-token exp-ssh-v2-0001\n + o> readline() -> 4: + o> 383\n + o> readline() -> 384: + o> capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN\n + + $ cd .. $ hg --config experimental.sshpeer.advertise-v2=true --debug debugpeer ssh://user@dummy/server running * "*/tests/dummyssh" 'user@dummy' 'hg -R server serve --stdio' (glob) (no-windows !) @@ -578,95 +1045,210 @@ Command after upgrade to version 2 is processed - >>> with open('payload', 'wb') as fh: - ... fh.write(b'upgrade this-is-some-token proto=exp-ssh-v2-0001\n') - ... fh.write(b'hello\n') - ... fh.write(b'between\n') - ... fh.write(b'pairs 81\n') - ... fh.write(b'0000000000000000000000000000000000000000-0000000000000000000000000000000000000000') - ... fh.write(b'hello\n') - $ hg -R server serve --stdio < payload - upgraded this-is-some-token exp-ssh-v2-0001 - 383 - capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN - 384 - capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN + $ cd server + + $ hg debugwireproto --localssh --peer raw << EOF + > raw + > upgrade this-is-some-token proto=exp-ssh-v2-0001\n + > hello\n + > between\n + > pairs 81\n + > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 + > readline + > readline + > readline + > raw + > hello\n + > readline + > readline + > EOF + using raw connection to peer + i> write(153) -> None: + i> upgrade this-is-some-token proto=exp-ssh-v2-0001\n + i> hello\n + i> between\n + i> pairs 81\n + i> 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 + o> readline() -> 44: + o> upgraded this-is-some-token exp-ssh-v2-0001\n + o> readline() -> 4: + o> 383\n + o> readline() -> 384: + o> capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN\n + i> write(6) -> None: + i> hello\n + o> readline() -> 4: + o> 384\n + o> readline() -> 384: + o> capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN\n Multiple upgrades is not allowed - >>> with open('payload', 'wb') as fh: - ... fh.write(b'upgrade this-is-some-token proto=exp-ssh-v2-0001\n') - ... fh.write(b'hello\n') - ... fh.write(b'between\n') - ... fh.write(b'pairs 81\n') - ... fh.write(b'0000000000000000000000000000000000000000-0000000000000000000000000000000000000000') - ... fh.write(b'upgrade another-token proto=irrelevant\n') - ... fh.write(b'hello\n') - $ hg -R server serve --stdio < payload - upgraded this-is-some-token exp-ssh-v2-0001 - 383 - capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN - cannot upgrade protocols multiple times - - - + $ hg debugwireproto --localssh --peer raw << EOF + > raw + > upgrade this-is-some-token proto=exp-ssh-v2-0001\n + > hello\n + > between\n + > pairs 81\n + > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 + > readline + > readline + > readline + > raw + > upgrade another-token proto=irrelevant\n + > hello\n + > readline + > readavailable + > EOF + using raw connection to peer + i> write(153) -> None: + i> upgrade this-is-some-token proto=exp-ssh-v2-0001\n + i> hello\n + i> between\n + i> pairs 81\n + i> 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 + o> readline() -> 44: + o> upgraded this-is-some-token exp-ssh-v2-0001\n + o> readline() -> 4: + o> 383\n + o> readline() -> 384: + o> capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN\n + i> write(45) -> None: + i> upgrade another-token proto=irrelevant\n + i> hello\n + o> readline() -> 1: + o> \n + e> read(-1) -> 42: + e> cannot upgrade protocols multiple times\n + e> -\n Malformed upgrade request line (not exactly 3 space delimited tokens) - $ hg -R server serve --stdio << EOF - > upgrade + $ hg debugwireproto --localssh --peer raw << EOF + > raw + > upgrade\n + > readline > EOF - 0 + using raw connection to peer + i> write(8) -> None: + i> upgrade\n + o> readline() -> 2: + o> 0\n - $ hg -R server serve --stdio << EOF - > upgrade token + $ hg debugwireproto --localssh --peer raw << EOF + > raw + > upgrade token\n + > readline > EOF - 0 + using raw connection to peer + i> write(14) -> None: + i> upgrade token\n + o> readline() -> 2: + o> 0\n - $ hg -R server serve --stdio << EOF - > upgrade token foo=bar extra-token + $ hg debugwireproto --localssh --peer raw << EOF + > raw + > upgrade token foo=bar extra-token\n + > readline > EOF - 0 + using raw connection to peer + i> write(34) -> None: + i> upgrade token foo=bar extra-token\n + o> readline() -> 2: + o> 0\n Upgrade request to unsupported protocol is ignored - $ hg -R server serve --stdio << EOF - > upgrade this-is-some-token proto=unknown1,unknown2 - > hello - > between - > pairs 81 - > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 + $ hg debugwireproto --localssh --peer raw << EOF + > raw + > upgrade this-is-some-token proto=unknown1,unknown2\n + > readline + > raw + > hello\n + > readline + > readline + > raw + > between\n + > pairs 81\n + > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 + > readline + > readline > EOF - 0 - 384 - capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN - 1 - + using raw connection to peer + i> write(51) -> None: + i> upgrade this-is-some-token proto=unknown1,unknown2\n + o> readline() -> 2: + o> 0\n + i> write(6) -> None: + i> hello\n + o> readline() -> 4: + o> 384\n + o> readline() -> 384: + o> capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN\n + i> write(98) -> None: + i> between\n + i> pairs 81\n + i> 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 + o> readline() -> 2: + o> 1\n + o> readline() -> 1: + o> \n Upgrade request must be followed by hello + between - $ hg -R server serve --stdio << EOF - > upgrade token proto=exp-ssh-v2-0001 - > invalid + $ hg debugwireproto --localssh --peer raw << EOF + > raw + > upgrade token proto=exp-ssh-v2-0001\n + > invalid\n + > readline + > readavailable > EOF - malformed handshake protocol: missing hello - - - + using raw connection to peer + i> write(44) -> None: + i> upgrade token proto=exp-ssh-v2-0001\n + i> invalid\n + o> readline() -> 1: + o> \n + e> read(-1) -> 46: + e> malformed handshake protocol: missing hello\n + e> -\n - $ hg -R server serve --stdio << EOF - > upgrade token proto=exp-ssh-v2-0001 - > hello - > invalid + $ hg debugwireproto --localssh --peer raw << EOF + > raw + > upgrade token proto=exp-ssh-v2-0001\n + > hello\n + > invalid\n + > readline + > readavailable > EOF - malformed handshake protocol: missing between - - - + using raw connection to peer + i> write(50) -> None: + i> upgrade token proto=exp-ssh-v2-0001\n + i> hello\n + i> invalid\n + o> readline() -> 1: + o> \n + e> read(-1) -> 48: + e> malformed handshake protocol: missing between\n + e> -\n - $ hg -R server serve --stdio << EOF - > upgrade token proto=exp-ssh-v2-0001 - > hello - > between - > invalid + $ hg debugwireproto --localssh --peer raw << EOF + > raw + > upgrade token proto=exp-ssh-v2-0001\n + > hello\n + > between\n + > invalid\n + > readline + > readavailable > EOF - malformed handshake protocol: missing pairs 81 - - - + using raw connection to peer + i> write(58) -> None: + i> upgrade token proto=exp-ssh-v2-0001\n + i> hello\n + i> between\n + i> invalid\n + o> readline() -> 1: + o> \n + e> read(-1) -> 49: + e> malformed handshake protocol: missing pairs 81\n + e> -\n