##// END OF EJS Templates
sshpeer: remove support for connecting to <0.9.1 servers (BC)...
Gregory Szorc -
r35958:556218e0 default
parent child Browse files
Show More
@@ -1,456 +1,466 b''
1 1 # sshpeer.py - ssh repository proxy class for mercurial
2 2 #
3 3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from __future__ import absolute_import
9 9
10 10 import re
11 11
12 12 from .i18n import _
13 13 from . import (
14 14 error,
15 15 pycompat,
16 16 util,
17 17 wireproto,
18 18 )
19 19
20 20 def _serverquote(s):
21 21 """quote a string for the remote shell ... which we assume is sh"""
22 22 if not s:
23 23 return s
24 24 if re.match('[a-zA-Z0-9@%_+=:,./-]*$', s):
25 25 return s
26 26 return "'%s'" % s.replace("'", "'\\''")
27 27
28 28 def _forwardoutput(ui, pipe):
29 29 """display all data currently available on pipe as remote output.
30 30
31 31 This is non blocking."""
32 32 s = util.readpipe(pipe)
33 33 if s:
34 34 for l in s.splitlines():
35 35 ui.status(_("remote: "), l, '\n')
36 36
37 37 class doublepipe(object):
38 38 """Operate a side-channel pipe in addition of a main one
39 39
40 40 The side-channel pipe contains server output to be forwarded to the user
41 41 input. The double pipe will behave as the "main" pipe, but will ensure the
42 42 content of the "side" pipe is properly processed while we wait for blocking
43 43 call on the "main" pipe.
44 44
45 45 If large amounts of data are read from "main", the forward will cease after
46 46 the first bytes start to appear. This simplifies the implementation
47 47 without affecting actual output of sshpeer too much as we rarely issue
48 48 large read for data not yet emitted by the server.
49 49
50 50 The main pipe is expected to be a 'bufferedinputpipe' from the util module
51 51 that handle all the os specific bits. This class lives in this module
52 52 because it focus on behavior specific to the ssh protocol."""
53 53
54 54 def __init__(self, ui, main, side):
55 55 self._ui = ui
56 56 self._main = main
57 57 self._side = side
58 58
59 59 def _wait(self):
60 60 """wait until some data are available on main or side
61 61
62 62 return a pair of boolean (ismainready, issideready)
63 63
64 64 (This will only wait for data if the setup is supported by `util.poll`)
65 65 """
66 66 if getattr(self._main, 'hasbuffer', False): # getattr for classic pipe
67 67 return (True, True) # main has data, assume side is worth poking at.
68 68 fds = [self._main.fileno(), self._side.fileno()]
69 69 try:
70 70 act = util.poll(fds)
71 71 except NotImplementedError:
72 72 # non supported yet case, assume all have data.
73 73 act = fds
74 74 return (self._main.fileno() in act, self._side.fileno() in act)
75 75
76 76 def write(self, data):
77 77 return self._call('write', data)
78 78
79 79 def read(self, size):
80 80 r = self._call('read', size)
81 81 if size != 0 and not r:
82 82 # We've observed a condition that indicates the
83 83 # stdout closed unexpectedly. Check stderr one
84 84 # more time and snag anything that's there before
85 85 # letting anyone know the main part of the pipe
86 86 # closed prematurely.
87 87 _forwardoutput(self._ui, self._side)
88 88 return r
89 89
90 90 def readline(self):
91 91 return self._call('readline')
92 92
93 93 def _call(self, methname, data=None):
94 94 """call <methname> on "main", forward output of "side" while blocking
95 95 """
96 96 # data can be '' or 0
97 97 if (data is not None and not data) or self._main.closed:
98 98 _forwardoutput(self._ui, self._side)
99 99 return ''
100 100 while True:
101 101 mainready, sideready = self._wait()
102 102 if sideready:
103 103 _forwardoutput(self._ui, self._side)
104 104 if mainready:
105 105 meth = getattr(self._main, methname)
106 106 if data is None:
107 107 return meth()
108 108 else:
109 109 return meth(data)
110 110
111 111 def close(self):
112 112 return self._main.close()
113 113
114 114 def flush(self):
115 115 return self._main.flush()
116 116
117 117 def _cleanuppipes(ui, pipei, pipeo, pipee):
118 118 """Clean up pipes used by an SSH connection."""
119 119 if pipeo:
120 120 pipeo.close()
121 121 if pipei:
122 122 pipei.close()
123 123
124 124 if pipee:
125 125 # Try to read from the err descriptor until EOF.
126 126 try:
127 127 for l in pipee:
128 128 ui.status(_('remote: '), l)
129 129 except (IOError, ValueError):
130 130 pass
131 131
132 132 pipee.close()
133 133
134 134 def _makeconnection(ui, sshcmd, args, remotecmd, path, sshenv=None):
135 135 """Create an SSH connection to a server.
136 136
137 137 Returns a tuple of (process, stdin, stdout, stderr) for the
138 138 spawned process.
139 139 """
140 140 cmd = '%s %s %s' % (
141 141 sshcmd,
142 142 args,
143 143 util.shellquote('%s -R %s serve --stdio' % (
144 144 _serverquote(remotecmd), _serverquote(path))))
145 145
146 146 ui.debug('running %s\n' % cmd)
147 147 cmd = util.quotecommand(cmd)
148 148
149 149 # no buffer allow the use of 'select'
150 150 # feel free to remove buffering and select usage when we ultimately
151 151 # move to threading.
152 152 stdin, stdout, stderr, proc = util.popen4(cmd, bufsize=0, env=sshenv)
153 153
154 154 stdout = doublepipe(ui, util.bufferedinputpipe(stdout), stderr)
155 155 stdin = doublepipe(ui, stdin, stderr)
156 156
157 157 return proc, stdin, stdout, stderr
158 158
159 159 def _performhandshake(ui, stdin, stdout, stderr):
160 160 def badresponse():
161 161 msg = _('no suitable response from remote hg')
162 162 hint = ui.config('ui', 'ssherrorhint')
163 163 raise error.RepoError(msg, hint=hint)
164 164
165 165 # The handshake consists of sending 2 wire protocol commands:
166 166 # ``hello`` and ``between``.
167 167 #
168 168 # The ``hello`` command (which was introduced in Mercurial 0.9.1)
169 169 # instructs the server to advertise its capabilities.
170 170 #
171 171 # The ``between`` command (which has existed in all Mercurial servers
172 172 # for as long as SSH support has existed), asks for the set of revisions
173 173 # between a pair of revisions.
174 174 #
175 175 # The ``between`` command is issued with a request for the null
176 176 # range. If the remote is a Mercurial server, this request will
177 177 # generate a specific response: ``1\n\n``. This represents the
178 178 # wire protocol encoded value for ``\n``. We look for ``1\n\n``
179 179 # in the output stream and know this is the response to ``between``
180 180 # and we're at the end of our handshake reply.
181 181 #
182 182 # The response to the ``hello`` command will be a line with the
183 183 # length of the value returned by that command followed by that
184 184 # value. If the server doesn't support ``hello`` (which should be
185 185 # rare), that line will be ``0\n``. Otherwise, the value will contain
186 186 # RFC 822 like lines. Of these, the ``capabilities:`` line contains
187 187 # the capabilities of the server.
188 188 #
189 189 # In addition to the responses to our command requests, the server
190 190 # may emit "banner" output on stdout. SSH servers are allowed to
191 191 # print messages to stdout on login. Issuing commands on connection
192 192 # allows us to flush this banner output from the server by scanning
193 193 # for output to our well-known ``between`` command. Of course, if
194 194 # the banner contains ``1\n\n``, this will throw off our detection.
195 195
196 196 requestlog = ui.configbool('devel', 'debug.peer-request')
197 197
198 198 try:
199 199 pairsarg = '%s-%s' % ('0' * 40, '0' * 40)
200 200 handshake = [
201 201 'hello\n',
202 202 'between\n',
203 203 'pairs %d\n' % len(pairsarg),
204 204 pairsarg,
205 205 ]
206 206
207 207 if requestlog:
208 208 ui.debug('devel-peer-request: hello\n')
209 209 ui.debug('sending hello command\n')
210 210 if requestlog:
211 211 ui.debug('devel-peer-request: between\n')
212 212 ui.debug('devel-peer-request: pairs: %d bytes\n' % len(pairsarg))
213 213 ui.debug('sending between command\n')
214 214
215 215 stdin.write(''.join(handshake))
216 216 stdin.flush()
217 217 except IOError:
218 218 badresponse()
219 219
220 220 lines = ['', 'dummy']
221 221 max_noise = 500
222 222 while lines[-1] and max_noise:
223 223 try:
224 224 l = stdout.readline()
225 225 _forwardoutput(ui, stderr)
226 226 if lines[-1] == '1\n' and l == '\n':
227 227 break
228 228 if l:
229 229 ui.debug('remote: ', l)
230 230 lines.append(l)
231 231 max_noise -= 1
232 232 except IOError:
233 233 badresponse()
234 234 else:
235 235 badresponse()
236 236
237 237 caps = set()
238 238 for l in reversed(lines):
239 239 # Look for response to ``hello`` command. Scan from the back so
240 240 # we don't misinterpret banner output as the command reply.
241 241 if l.startswith('capabilities:'):
242 242 caps.update(l[:-1].split(':')[1].split())
243 243 break
244 244
245 # Error if we couldn't find a response to ``hello``. This could
246 # mean:
247 #
248 # 1. Remote isn't a Mercurial server
249 # 2. Remote is a <0.9.1 Mercurial server
250 # 3. Remote is a future Mercurial server that dropped ``hello``
251 # support.
252 if not caps:
253 badresponse()
254
245 255 return caps
246 256
247 257 class sshpeer(wireproto.wirepeer):
248 258 def __init__(self, ui, url, proc, stdin, stdout, stderr, caps):
249 259 """Create a peer from an existing SSH connection.
250 260
251 261 ``proc`` is a handle on the underlying SSH process.
252 262 ``stdin``, ``stdout``, and ``stderr`` are handles on the stdio
253 263 pipes for that process.
254 264 ``caps`` is a set of capabilities supported by the remote.
255 265 """
256 266 self._url = url
257 267 self._ui = ui
258 268 # self._subprocess is unused. Keeping a handle on the process
259 269 # holds a reference and prevents it from being garbage collected.
260 270 self._subprocess = proc
261 271 self._pipeo = stdin
262 272 self._pipei = stdout
263 273 self._pipee = stderr
264 274 self._caps = caps
265 275
266 276 # Begin of _basepeer interface.
267 277
268 278 @util.propertycache
269 279 def ui(self):
270 280 return self._ui
271 281
272 282 def url(self):
273 283 return self._url
274 284
275 285 def local(self):
276 286 return None
277 287
278 288 def peer(self):
279 289 return self
280 290
281 291 def canpush(self):
282 292 return True
283 293
284 294 def close(self):
285 295 pass
286 296
287 297 # End of _basepeer interface.
288 298
289 299 # Begin of _basewirecommands interface.
290 300
291 301 def capabilities(self):
292 302 return self._caps
293 303
294 304 # End of _basewirecommands interface.
295 305
296 306 def _readerr(self):
297 307 _forwardoutput(self.ui, self._pipee)
298 308
299 309 def _abort(self, exception):
300 310 self._cleanup()
301 311 raise exception
302 312
303 313 def _cleanup(self):
304 314 _cleanuppipes(self.ui, self._pipei, self._pipeo, self._pipee)
305 315
306 316 __del__ = _cleanup
307 317
308 318 def _submitbatch(self, req):
309 319 rsp = self._callstream("batch", cmds=wireproto.encodebatchcmds(req))
310 320 available = self._getamount()
311 321 # TODO this response parsing is probably suboptimal for large
312 322 # batches with large responses.
313 323 toread = min(available, 1024)
314 324 work = rsp.read(toread)
315 325 available -= toread
316 326 chunk = work
317 327 while chunk:
318 328 while ';' in work:
319 329 one, work = work.split(';', 1)
320 330 yield wireproto.unescapearg(one)
321 331 toread = min(available, 1024)
322 332 chunk = rsp.read(toread)
323 333 available -= toread
324 334 work += chunk
325 335 yield wireproto.unescapearg(work)
326 336
327 337 def _callstream(self, cmd, **args):
328 338 args = pycompat.byteskwargs(args)
329 339 if (self.ui.debugflag
330 340 and self.ui.configbool('devel', 'debug.peer-request')):
331 341 dbg = self.ui.debug
332 342 line = 'devel-peer-request: %s\n'
333 343 dbg(line % cmd)
334 344 for key, value in sorted(args.items()):
335 345 if not isinstance(value, dict):
336 346 dbg(line % ' %s: %d bytes' % (key, len(value)))
337 347 else:
338 348 for dk, dv in sorted(value.items()):
339 349 dbg(line % ' %s-%s: %d' % (key, dk, len(dv)))
340 350 self.ui.debug("sending %s command\n" % cmd)
341 351 self._pipeo.write("%s\n" % cmd)
342 352 _func, names = wireproto.commands[cmd]
343 353 keys = names.split()
344 354 wireargs = {}
345 355 for k in keys:
346 356 if k == '*':
347 357 wireargs['*'] = args
348 358 break
349 359 else:
350 360 wireargs[k] = args[k]
351 361 del args[k]
352 362 for k, v in sorted(wireargs.iteritems()):
353 363 self._pipeo.write("%s %d\n" % (k, len(v)))
354 364 if isinstance(v, dict):
355 365 for dk, dv in v.iteritems():
356 366 self._pipeo.write("%s %d\n" % (dk, len(dv)))
357 367 self._pipeo.write(dv)
358 368 else:
359 369 self._pipeo.write(v)
360 370 self._pipeo.flush()
361 371
362 372 return self._pipei
363 373
364 374 def _callcompressable(self, cmd, **args):
365 375 return self._callstream(cmd, **args)
366 376
367 377 def _call(self, cmd, **args):
368 378 self._callstream(cmd, **args)
369 379 return self._recv()
370 380
371 381 def _callpush(self, cmd, fp, **args):
372 382 r = self._call(cmd, **args)
373 383 if r:
374 384 return '', r
375 385 for d in iter(lambda: fp.read(4096), ''):
376 386 self._send(d)
377 387 self._send("", flush=True)
378 388 r = self._recv()
379 389 if r:
380 390 return '', r
381 391 return self._recv(), ''
382 392
383 393 def _calltwowaystream(self, cmd, fp, **args):
384 394 r = self._call(cmd, **args)
385 395 if r:
386 396 # XXX needs to be made better
387 397 raise error.Abort(_('unexpected remote reply: %s') % r)
388 398 for d in iter(lambda: fp.read(4096), ''):
389 399 self._send(d)
390 400 self._send("", flush=True)
391 401 return self._pipei
392 402
393 403 def _getamount(self):
394 404 l = self._pipei.readline()
395 405 if l == '\n':
396 406 self._readerr()
397 407 msg = _('check previous remote output')
398 408 self._abort(error.OutOfBandError(hint=msg))
399 409 self._readerr()
400 410 try:
401 411 return int(l)
402 412 except ValueError:
403 413 self._abort(error.ResponseError(_("unexpected response:"), l))
404 414
405 415 def _recv(self):
406 416 return self._pipei.read(self._getamount())
407 417
408 418 def _send(self, data, flush=False):
409 419 self._pipeo.write("%d\n" % len(data))
410 420 if data:
411 421 self._pipeo.write(data)
412 422 if flush:
413 423 self._pipeo.flush()
414 424 self._readerr()
415 425
416 426 def instance(ui, path, create):
417 427 """Create an SSH peer.
418 428
419 429 The returned object conforms to the ``wireproto.wirepeer`` interface.
420 430 """
421 431 u = util.url(path, parsequery=False, parsefragment=False)
422 432 if u.scheme != 'ssh' or not u.host or u.path is None:
423 433 raise error.RepoError(_("couldn't parse location %s") % path)
424 434
425 435 util.checksafessh(path)
426 436
427 437 if u.passwd is not None:
428 438 raise error.RepoError(_('password in URL not supported'))
429 439
430 440 sshcmd = ui.config('ui', 'ssh')
431 441 remotecmd = ui.config('ui', 'remotecmd')
432 442 sshaddenv = dict(ui.configitems('sshenv'))
433 443 sshenv = util.shellenviron(sshaddenv)
434 444 remotepath = u.path or '.'
435 445
436 446 args = util.sshargs(sshcmd, u.host, u.user, u.port)
437 447
438 448 if create:
439 449 cmd = '%s %s %s' % (sshcmd, args,
440 450 util.shellquote('%s init %s' %
441 451 (_serverquote(remotecmd), _serverquote(remotepath))))
442 452 ui.debug('running %s\n' % cmd)
443 453 res = ui.system(cmd, blockedtag='sshpeer', environ=sshenv)
444 454 if res != 0:
445 455 raise error.RepoError(_('could not create remote repo'))
446 456
447 457 proc, stdin, stdout, stderr = _makeconnection(ui, sshcmd, args, remotecmd,
448 458 remotepath, sshenv)
449 459
450 460 try:
451 461 caps = _performhandshake(ui, stdin, stdout, stderr)
452 462 except Exception:
453 463 _cleanuppipes(ui, stdout, stdin, stderr)
454 464 raise
455 465
456 466 return sshpeer(ui, path, proc, stdin, stdout, stderr, caps)
@@ -1,394 +1,390 b''
1 1 $ cat >> $HGRCPATH << EOF
2 2 > [ui]
3 3 > ssh = $PYTHON "$TESTDIR/dummyssh"
4 4 > [devel]
5 5 > debug.peer-request = true
6 6 > [extensions]
7 7 > sshprotoext = $TESTDIR/sshprotoext.py
8 8 > EOF
9 9
10 10 $ hg init server
11 11 $ cd server
12 12 $ echo 0 > foo
13 13 $ hg -q add foo
14 14 $ hg commit -m initial
15 15 $ cd ..
16 16
17 17 Test a normal behaving server, for sanity
18 18
19 19 $ hg --debug debugpeer ssh://user@dummy/server
20 20 running * "*/tests/dummyssh" 'user@dummy' 'hg -R server serve --stdio' (glob)
21 21 devel-peer-request: hello
22 22 sending hello command
23 23 devel-peer-request: between
24 24 devel-peer-request: pairs: 81 bytes
25 25 sending between command
26 26 remote: 384
27 27 remote: capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN
28 28 remote: 1
29 29 url: ssh://user@dummy/server
30 30 local: no
31 31 pushable: yes
32 32
33 33 Server should answer the "hello" command in isolation
34 34
35 35 $ hg -R server serve --stdio << EOF
36 36 > hello
37 37 > EOF
38 38 384
39 39 capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN
40 40
41 41 >=0.9.1 clients send a "hello" + "between" for the null range as part of handshake.
42 42 Server should reply with capabilities and should send "1\n\n" as a successful
43 43 reply with empty response to the "between".
44 44
45 45 $ hg -R server serve --stdio << EOF
46 46 > hello
47 47 > between
48 48 > pairs 81
49 49 > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
50 50 > EOF
51 51 384
52 52 capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN
53 53 1
54 54
55 55
56 56 SSH banner is not printed by default, ignored by clients
57 57
58 58 $ SSHSERVERMODE=banner hg debugpeer ssh://user@dummy/server
59 59 url: ssh://user@dummy/server
60 60 local: no
61 61 pushable: yes
62 62
63 63 --debug will print the banner
64 64
65 65 $ SSHSERVERMODE=banner hg --debug debugpeer ssh://user@dummy/server
66 66 running * "*/tests/dummyssh" 'user@dummy' 'hg -R server serve --stdio' (glob)
67 67 devel-peer-request: hello
68 68 sending hello command
69 69 devel-peer-request: between
70 70 devel-peer-request: pairs: 81 bytes
71 71 sending between command
72 72 remote: banner: line 0
73 73 remote: banner: line 1
74 74 remote: banner: line 2
75 75 remote: banner: line 3
76 76 remote: banner: line 4
77 77 remote: banner: line 5
78 78 remote: banner: line 6
79 79 remote: banner: line 7
80 80 remote: banner: line 8
81 81 remote: banner: line 9
82 82 remote: 384
83 83 remote: capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN
84 84 remote: 1
85 85 url: ssh://user@dummy/server
86 86 local: no
87 87 pushable: yes
88 88
89 89 And test the banner with the raw protocol
90 90
91 91 $ SSHSERVERMODE=banner hg -R server serve --stdio << EOF
92 92 > hello
93 93 > between
94 94 > pairs 81
95 95 > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
96 96 > EOF
97 97 banner: line 0
98 98 banner: line 1
99 99 banner: line 2
100 100 banner: line 3
101 101 banner: line 4
102 102 banner: line 5
103 103 banner: line 6
104 104 banner: line 7
105 105 banner: line 8
106 106 banner: line 9
107 107 384
108 108 capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN
109 109 1
110 110
111 111
112 Connecting to a <0.9.1 server that doesn't support the hello command
112 Connecting to a <0.9.1 server that doesn't support the hello command.
113 The client should refuse, as we dropped support for connecting to such
114 servers.
113 115
114 116 $ SSHSERVERMODE=no-hello hg --debug debugpeer ssh://user@dummy/server
115 117 running * "*/tests/dummyssh" 'user@dummy' 'hg -R server serve --stdio' (glob)
116 118 devel-peer-request: hello
117 119 sending hello command
118 120 devel-peer-request: between
119 121 devel-peer-request: pairs: 81 bytes
120 122 sending between command
121 123 remote: 0
122 124 remote: 1
123 url: ssh://user@dummy/server
124 local: no
125 pushable: yes
126
127 The client should interpret this as no capabilities
128
129 $ SSHSERVERMODE=no-hello hg debugcapabilities ssh://user@dummy/server
130 Main capabilities:
125 abort: no suitable response from remote hg!
126 [255]
131 127
132 128 Sending an unknown command to the server results in an empty response to that command
133 129
134 130 $ hg -R server serve --stdio << EOF
135 131 > pre-hello
136 132 > hello
137 133 > between
138 134 > pairs 81
139 135 > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
140 136 > EOF
141 137 0
142 138 384
143 139 capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN
144 140 1
145 141
146 142
147 143 $ hg --config sshpeer.mode=extra-handshake-commands --config sshpeer.handshake-mode=pre-no-args --debug debugpeer ssh://user@dummy/server
148 144 running * "*/tests/dummyssh" 'user@dummy' 'hg -R server serve --stdio' (glob)
149 145 sending no-args command
150 146 devel-peer-request: hello
151 147 sending hello command
152 148 devel-peer-request: between
153 149 devel-peer-request: pairs: 81 bytes
154 150 sending between command
155 151 remote: 0
156 152 remote: 384
157 153 remote: capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN
158 154 remote: 1
159 155 url: ssh://user@dummy/server
160 156 local: no
161 157 pushable: yes
162 158
163 159 Send multiple unknown commands before hello
164 160
165 161 $ hg -R server serve --stdio << EOF
166 162 > unknown1
167 163 > unknown2
168 164 > unknown3
169 165 > hello
170 166 > between
171 167 > pairs 81
172 168 > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
173 169 > EOF
174 170 0
175 171 0
176 172 0
177 173 384
178 174 capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN
179 175 1
180 176
181 177
182 178 $ hg --config sshpeer.mode=extra-handshake-commands --config sshpeer.handshake-mode=pre-multiple-no-args --debug debugpeer ssh://user@dummy/server
183 179 running * "*/tests/dummyssh" 'user@dummy' 'hg -R server serve --stdio' (glob)
184 180 sending unknown1 command
185 181 sending unknown2 command
186 182 sending unknown3 command
187 183 devel-peer-request: hello
188 184 sending hello command
189 185 devel-peer-request: between
190 186 devel-peer-request: pairs: 81 bytes
191 187 sending between command
192 188 remote: 0
193 189 remote: 0
194 190 remote: 0
195 191 remote: 384
196 192 remote: capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN
197 193 remote: 1
198 194 url: ssh://user@dummy/server
199 195 local: no
200 196 pushable: yes
201 197
202 198 Send an unknown command before hello that has arguments
203 199
204 200 $ hg -R server serve --stdio << EOF
205 201 > with-args
206 202 > foo 13
207 203 > value for foo
208 204 > bar 13
209 205 > value for bar
210 206 > hello
211 207 > between
212 208 > pairs 81
213 209 > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
214 210 > EOF
215 211 0
216 212 0
217 213 0
218 214 0
219 215 0
220 216 384
221 217 capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN
222 218 1
223 219
224 220
225 221 Send an unknown command having an argument that looks numeric
226 222
227 223 $ hg -R server serve --stdio << EOF
228 224 > unknown
229 225 > foo 1
230 226 > 0
231 227 > hello
232 228 > between
233 229 > pairs 81
234 230 > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
235 231 > EOF
236 232 0
237 233 0
238 234 0
239 235 384
240 236 capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN
241 237 1
242 238
243 239
244 240 $ hg -R server serve --stdio << EOF
245 241 > unknown
246 242 > foo 1
247 243 > 1
248 244 > hello
249 245 > between
250 246 > pairs 81
251 247 > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
252 248 > EOF
253 249 0
254 250 0
255 251 0
256 252 384
257 253 capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN
258 254 1
259 255
260 256
261 257 When sending a dict argument value, it is serialized to
262 258 "<arg> <item count>" followed by "<key> <len>\n<value>" for each item
263 259 in the dict.
264 260
265 261 Dictionary value for unknown command
266 262
267 263 $ hg -R server serve --stdio << EOF
268 264 > unknown
269 265 > dict 3
270 266 > key1 3
271 267 > foo
272 268 > key2 3
273 269 > bar
274 270 > key3 3
275 271 > baz
276 272 > hello
277 273 > EOF
278 274 0
279 275 0
280 276 0
281 277 0
282 278 0
283 279 0
284 280 0
285 281 0
286 282 384
287 283 capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN
288 284
289 285 Incomplete dictionary send
290 286
291 287 $ hg -R server serve --stdio << EOF
292 288 > unknown
293 289 > dict 3
294 290 > key1 3
295 291 > foo
296 292 > EOF
297 293 0
298 294 0
299 295 0
300 296 0
301 297
302 298 Incomplete value send
303 299
304 300 $ hg -R server serve --stdio << EOF
305 301 > unknown
306 302 > dict 3
307 303 > key1 3
308 304 > fo
309 305 > EOF
310 306 0
311 307 0
312 308 0
313 309 0
314 310
315 311 Send a command line with spaces
316 312
317 313 $ hg -R server serve --stdio << EOF
318 314 > unknown withspace
319 315 > hello
320 316 > between
321 317 > pairs 81
322 318 > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
323 319 > EOF
324 320 0
325 321 384
326 322 capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN
327 323 1
328 324
329 325
330 326 $ hg -R server serve --stdio << EOF
331 327 > unknown with multiple spaces
332 328 > hello
333 329 > between
334 330 > pairs 81
335 331 > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
336 332 > EOF
337 333 0
338 334 384
339 335 capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN
340 336 1
341 337
342 338
343 339 $ hg -R server serve --stdio << EOF
344 340 > unknown with spaces
345 341 > key 10
346 342 > some value
347 343 > hello
348 344 > between
349 345 > pairs 81
350 346 > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
351 347 > EOF
352 348 0
353 349 0
354 350 0
355 351 384
356 352 capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN
357 353 1
358 354
359 355
360 356 Send an unknown command after the "between"
361 357
362 358 $ hg -R server serve --stdio << EOF
363 359 > hello
364 360 > between
365 361 > pairs 81
366 362 > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000unknown
367 363 > EOF
368 364 384
369 365 capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN
370 366 1
371 367
372 368 0
373 369
374 370 And one with arguments
375 371
376 372 $ hg -R server serve --stdio << EOF
377 373 > hello
378 374 > between
379 375 > pairs 81
380 376 > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000unknown
381 377 > foo 5
382 378 > value
383 379 > bar 3
384 380 > baz
385 381 > EOF
386 382 384
387 383 capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN
388 384 1
389 385
390 386 0
391 387 0
392 388 0
393 389 0
394 390 0
General Comments 0
You need to be logged in to leave comments. Login now