Show More
@@ -574,6 +574,9 b" coreconfigitem('experimental', 'treemani" | |||||
574 | coreconfigitem('experimental', 'update.atomic-file', |
|
574 | coreconfigitem('experimental', 'update.atomic-file', | |
575 | default=False, |
|
575 | default=False, | |
576 | ) |
|
576 | ) | |
|
577 | coreconfigitem('experimental', 'sshpeer.advertise-v2', | |||
|
578 | default=False, | |||
|
579 | ) | |||
577 | coreconfigitem('extensions', '.*', |
|
580 | coreconfigitem('extensions', '.*', | |
578 | default=None, |
|
581 | default=None, | |
579 | generic=True, |
|
582 | generic=True, |
@@ -218,6 +218,95 b' part of the response payload and not par' | |||||
218 | after responses. In other words, the length of the response contains the |
|
218 | after responses. In other words, the length of the response contains the | |
219 | trailing ``\n``. |
|
219 | trailing ``\n``. | |
220 |
|
220 | |||
|
221 | Clients supporting version 2 of the SSH transport send a line beginning | |||
|
222 | with ``upgrade`` before the ``hello`` and ``between`` commands. The line | |||
|
223 | (which isn't a well-formed command line because it doesn't consist of a | |||
|
224 | single command name) serves to both communicate the client's intent to | |||
|
225 | switch to transport version 2 (transports are version 1 by default) as | |||
|
226 | well as to advertise the client's transport-level capabilities so the | |||
|
227 | server may satisfy that request immediately. | |||
|
228 | ||||
|
229 | The upgrade line has the form: | |||
|
230 | ||||
|
231 | upgrade <token> <transport capabilities> | |||
|
232 | ||||
|
233 | That is the literal string ``upgrade`` followed by a space, followed by | |||
|
234 | a randomly generated string, followed by a space, followed by a string | |||
|
235 | denoting the client's transport capabilities. | |||
|
236 | ||||
|
237 | The token can be anything. However, a random UUID is recommended. (Use | |||
|
238 | of version 4 UUIDs is recommended because version 1 UUIDs can leak the | |||
|
239 | client's MAC address.) | |||
|
240 | ||||
|
241 | The transport capabilities string is a URL/percent encoded string | |||
|
242 | containing key-value pairs defining the client's transport-level | |||
|
243 | capabilities. The following capabilities are defined: | |||
|
244 | ||||
|
245 | proto | |||
|
246 | A comma-delimited list of transport protocol versions the client | |||
|
247 | supports. e.g. ``ssh-v2``. | |||
|
248 | ||||
|
249 | If the server does not recognize the ``upgrade`` line, it should issue | |||
|
250 | an empty response and continue processing the ``hello`` and ``between`` | |||
|
251 | commands. Here is an example handshake between a version 2 aware client | |||
|
252 | and a non version 2 aware server: | |||
|
253 | ||||
|
254 | c: upgrade 2e82ab3f-9ce3-4b4e-8f8c-6fd1c0e9e23a proto=ssh-v2 | |||
|
255 | c: hello\n | |||
|
256 | c: between\n | |||
|
257 | c: pairs 81\n | |||
|
258 | c: 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 | |||
|
259 | s: 0\n | |||
|
260 | s: 324\n | |||
|
261 | s: capabilities: lookup changegroupsubset branchmap pushkey known getbundle ...\n | |||
|
262 | s: 1\n | |||
|
263 | s: \n | |||
|
264 | ||||
|
265 | (The initial ``0\n`` line from the server indicates an empty response to | |||
|
266 | the unknown ``upgrade ..`` command/line.) | |||
|
267 | ||||
|
268 | If the server recognizes the ``upgrade`` line and is willing to satisfy that | |||
|
269 | upgrade request, it replies to with a payload of the following form: | |||
|
270 | ||||
|
271 | upgraded <token> <transport name>\n | |||
|
272 | ||||
|
273 | This line is the literal string ``upgraded``, a space, the token that was | |||
|
274 | specified by the client in its ``upgrade ...`` request line, a space, and the | |||
|
275 | name of the transport protocol that was chosen by the server. The transport | |||
|
276 | name MUST match one of the names the client specified in the ``proto`` field | |||
|
277 | of its ``upgrade ...`` request line. | |||
|
278 | ||||
|
279 | If a server issues an ``upgraded`` response, it MUST also read and ignore | |||
|
280 | the lines associated with the ``hello`` and ``between`` command requests | |||
|
281 | that were issued by the server. It is assumed that the negotiated transport | |||
|
282 | will respond with equivalent requested information following the transport | |||
|
283 | handshake. | |||
|
284 | ||||
|
285 | All data following the ``\n`` terminating the ``upgraded`` line is the | |||
|
286 | domain of the negotiated transport. It is common for the data immediately | |||
|
287 | following to contain additional metadata about the state of the transport and | |||
|
288 | the server. However, this isn't strictly speaking part of the transport | |||
|
289 | handshake and isn't covered by this section. | |||
|
290 | ||||
|
291 | Here is an example handshake between a version 2 aware client and a version | |||
|
292 | 2 aware server: | |||
|
293 | ||||
|
294 | c: upgrade 2e82ab3f-9ce3-4b4e-8f8c-6fd1c0e9e23a proto=ssh-v2 | |||
|
295 | c: hello\n | |||
|
296 | c: between\n | |||
|
297 | c: pairs 81\n | |||
|
298 | c: 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 | |||
|
299 | s: upgraded 2e82ab3f-9ce3-4b4e-8f8c-6fd1c0e9e23a ssh-v2\n | |||
|
300 | s: <additional transport specific data> | |||
|
301 | ||||
|
302 | The client-issued token that is echoed in the response provides a more | |||
|
303 | resilient mechanism for differentiating *banner* output from Mercurial | |||
|
304 | output. In version 1, properly formatted banner output could get confused | |||
|
305 | for Mercurial server output. By submitting a randomly generated token | |||
|
306 | that is then present in the response, the client can look for that token | |||
|
307 | in response lines and have reasonable certainty that the line did not | |||
|
308 | originate from a *banner* message. | |||
|
309 | ||||
221 | SSH Version 1 Transport |
|
310 | SSH Version 1 Transport | |
222 | ----------------------- |
|
311 | ----------------------- | |
223 |
|
312 | |||
@@ -281,6 +370,31 b' response.' | |||||
281 |
|
370 | |||
282 | The server terminates if it receives an empty command (a ``\n`` character). |
|
371 | The server terminates if it receives an empty command (a ``\n`` character). | |
283 |
|
372 | |||
|
373 | SSH Version 2 Transport | |||
|
374 | ----------------------- | |||
|
375 | ||||
|
376 | **Experimental** | |||
|
377 | ||||
|
378 | Version 2 of the SSH transport behaves identically to version 1 of the SSH | |||
|
379 | transport with the exception of handshake semantics. See above for how | |||
|
380 | version 2 of the SSH transport is negotiated. | |||
|
381 | ||||
|
382 | Immediately following the ``upgraded`` line signaling a switch to version | |||
|
383 | 2 of the SSH protocol, the server automatically sends additional details | |||
|
384 | about the capabilities of the remote server. This has the form: | |||
|
385 | ||||
|
386 | <integer length of value>\n | |||
|
387 | capabilities: ...\n | |||
|
388 | ||||
|
389 | e.g. | |||
|
390 | ||||
|
391 | s: upgraded 2e82ab3f-9ce3-4b4e-8f8c-6fd1c0e9e23a ssh-v2\n | |||
|
392 | s: 240\n | |||
|
393 | s: capabilities: known getbundle batch ...\n | |||
|
394 | ||||
|
395 | Following capabilities advertisement, the peers communicate using version | |||
|
396 | 1 of the SSH transport. | |||
|
397 | ||||
284 | Capabilities |
|
398 | Capabilities | |
285 | ============ |
|
399 | ============ | |
286 |
|
400 |
@@ -8,6 +8,7 b'' | |||||
8 | from __future__ import absolute_import |
|
8 | from __future__ import absolute_import | |
9 |
|
9 | |||
10 | import re |
|
10 | import re | |
|
11 | import uuid | |||
11 |
|
12 | |||
12 | from .i18n import _ |
|
13 | from .i18n import _ | |
13 | from . import ( |
|
14 | from . import ( | |
@@ -15,6 +16,7 b' from . import (' | |||||
15 | pycompat, |
|
16 | pycompat, | |
16 | util, |
|
17 | util, | |
17 | wireproto, |
|
18 | wireproto, | |
|
19 | wireprotoserver, | |||
18 | ) |
|
20 | ) | |
19 |
|
21 | |||
20 | def _serverquote(s): |
|
22 | def _serverquote(s): | |
@@ -162,15 +164,24 b' def _performhandshake(ui, stdin, stdout,' | |||||
162 | hint = ui.config('ui', 'ssherrorhint') |
|
164 | hint = ui.config('ui', 'ssherrorhint') | |
163 | raise error.RepoError(msg, hint=hint) |
|
165 | raise error.RepoError(msg, hint=hint) | |
164 |
|
166 | |||
165 |
# The handshake consists of sending |
|
167 | # The handshake consists of sending wire protocol commands in reverse | |
166 | # ``hello`` and ``between``. |
|
168 | # order of protocol implementation and then sniffing for a response | |
|
169 | # to one of them. | |||
|
170 | # | |||
|
171 | # Those commands (from oldest to newest) are: | |||
167 | # |
|
172 | # | |
168 | # The ``hello`` command (which was introduced in Mercurial 0.9.1) |
|
173 | # ``between`` | |
169 | # instructs the server to advertise its capabilities. |
|
174 | # Asks for the set of revisions between a pair of revisions. Command | |
|
175 | # present in all Mercurial server implementations. | |||
170 | # |
|
176 | # | |
171 | # The ``between`` command (which has existed in all Mercurial servers |
|
177 | # ``hello`` | |
172 | # for as long as SSH support has existed), asks for the set of revisions |
|
178 | # Instructs the server to advertise its capabilities. Introduced in | |
173 | # between a pair of revisions. |
|
179 | # Mercurial 0.9.1. | |
|
180 | # | |||
|
181 | # ``upgrade`` | |||
|
182 | # Requests upgrade from default transport protocol version 1 to | |||
|
183 | # a newer version. Introduced in Mercurial 4.6 as an experimental | |||
|
184 | # feature. | |||
174 | # |
|
185 | # | |
175 | # The ``between`` command is issued with a request for the null |
|
186 | # The ``between`` command is issued with a request for the null | |
176 | # range. If the remote is a Mercurial server, this request will |
|
187 | # range. If the remote is a Mercurial server, this request will | |
@@ -186,6 +197,18 b' def _performhandshake(ui, stdin, stdout,' | |||||
186 | # RFC 822 like lines. Of these, the ``capabilities:`` line contains |
|
197 | # RFC 822 like lines. Of these, the ``capabilities:`` line contains | |
187 | # the capabilities of the server. |
|
198 | # the capabilities of the server. | |
188 | # |
|
199 | # | |
|
200 | # The ``upgrade`` command isn't really a command in the traditional | |||
|
201 | # sense of version 1 of the transport because it isn't using the | |||
|
202 | # proper mechanism for formatting insteads: instead, it just encodes | |||
|
203 | # arguments on the line, delimited by spaces. | |||
|
204 | # | |||
|
205 | # The ``upgrade`` line looks like ``upgrade <token> <capabilities>``. | |||
|
206 | # If the server doesn't support protocol upgrades, it will reply to | |||
|
207 | # this line with ``0\n``. Otherwise, it emits an | |||
|
208 | # ``upgraded <token> <protocol>`` line to both stdout and stderr. | |||
|
209 | # Content immediately following this line describes additional | |||
|
210 | # protocol and server state. | |||
|
211 | # | |||
189 | # In addition to the responses to our command requests, the server |
|
212 | # In addition to the responses to our command requests, the server | |
190 | # may emit "banner" output on stdout. SSH servers are allowed to |
|
213 | # may emit "banner" output on stdout. SSH servers are allowed to | |
191 | # print messages to stdout on login. Issuing commands on connection |
|
214 | # print messages to stdout on login. Issuing commands on connection | |
@@ -195,6 +218,14 b' def _performhandshake(ui, stdin, stdout,' | |||||
195 |
|
218 | |||
196 | requestlog = ui.configbool('devel', 'debug.peer-request') |
|
219 | requestlog = ui.configbool('devel', 'debug.peer-request') | |
197 |
|
220 | |||
|
221 | # Generate a random token to help identify responses to version 2 | |||
|
222 | # upgrade request. | |||
|
223 | token = bytes(uuid.uuid4()) | |||
|
224 | upgradecaps = [ | |||
|
225 | ('proto', wireprotoserver.SSHV2), | |||
|
226 | ] | |||
|
227 | upgradecaps = util.urlreq.urlencode(upgradecaps) | |||
|
228 | ||||
198 | try: |
|
229 | try: | |
199 | pairsarg = '%s-%s' % ('0' * 40, '0' * 40) |
|
230 | pairsarg = '%s-%s' % ('0' * 40, '0' * 40) | |
200 | handshake = [ |
|
231 | handshake = [ | |
@@ -204,6 +235,11 b' def _performhandshake(ui, stdin, stdout,' | |||||
204 | pairsarg, |
|
235 | pairsarg, | |
205 | ] |
|
236 | ] | |
206 |
|
237 | |||
|
238 | # Request upgrade to version 2 if configured. | |||
|
239 | if ui.configbool('experimental', 'sshpeer.advertise-v2'): | |||
|
240 | ui.debug('sending upgrade request: %s %s\n' % (token, upgradecaps)) | |||
|
241 | handshake.insert(0, 'upgrade %s %s\n' % (token, upgradecaps)) | |||
|
242 | ||||
207 | if requestlog: |
|
243 | if requestlog: | |
208 | ui.debug('devel-peer-request: hello\n') |
|
244 | ui.debug('devel-peer-request: hello\n') | |
209 | ui.debug('sending hello command\n') |
|
245 | ui.debug('sending hello command\n') | |
@@ -217,12 +253,31 b' def _performhandshake(ui, stdin, stdout,' | |||||
217 | except IOError: |
|
253 | except IOError: | |
218 | badresponse() |
|
254 | badresponse() | |
219 |
|
255 | |||
|
256 | # Assume version 1 of wire protocol by default. | |||
|
257 | protoname = wireprotoserver.SSHV1 | |||
|
258 | reupgraded = re.compile(b'^upgraded %s (.*)$' % re.escape(token)) | |||
|
259 | ||||
220 | lines = ['', 'dummy'] |
|
260 | lines = ['', 'dummy'] | |
221 | max_noise = 500 |
|
261 | max_noise = 500 | |
222 | while lines[-1] and max_noise: |
|
262 | while lines[-1] and max_noise: | |
223 | try: |
|
263 | try: | |
224 | l = stdout.readline() |
|
264 | l = stdout.readline() | |
225 | _forwardoutput(ui, stderr) |
|
265 | _forwardoutput(ui, stderr) | |
|
266 | ||||
|
267 | # Look for reply to protocol upgrade request. It has a token | |||
|
268 | # in it, so there should be no false positives. | |||
|
269 | m = reupgraded.match(l) | |||
|
270 | if m: | |||
|
271 | protoname = m.group(1) | |||
|
272 | ui.debug('protocol upgraded to %s\n' % protoname) | |||
|
273 | # If an upgrade was handled, the ``hello`` and ``between`` | |||
|
274 | # requests are ignored. The next output belongs to the | |||
|
275 | # protocol, so stop scanning lines. | |||
|
276 | break | |||
|
277 | ||||
|
278 | # Otherwise it could be a banner, ``0\n`` response if server | |||
|
279 | # doesn't support upgrade. | |||
|
280 | ||||
226 | if lines[-1] == '1\n' and l == '\n': |
|
281 | if lines[-1] == '1\n' and l == '\n': | |
227 | break |
|
282 | break | |
228 | if l: |
|
283 | if l: | |
@@ -235,20 +290,39 b' def _performhandshake(ui, stdin, stdout,' | |||||
235 | badresponse() |
|
290 | badresponse() | |
236 |
|
291 | |||
237 | caps = set() |
|
292 | caps = set() | |
238 | for l in reversed(lines): |
|
|||
239 | # Look for response to ``hello`` command. Scan from the back so |
|
|||
240 | # we don't misinterpret banner output as the command reply. |
|
|||
241 | if l.startswith('capabilities:'): |
|
|||
242 | caps.update(l[:-1].split(':')[1].split()) |
|
|||
243 | break |
|
|||
244 |
|
293 | |||
245 | # Error if we couldn't find a response to ``hello``. This could |
|
294 | # For version 1, we should see a ``capabilities`` line in response to the | |
246 | # mean: |
|
295 | # ``hello`` command. | |
|
296 | if protoname == wireprotoserver.SSHV1: | |||
|
297 | for l in reversed(lines): | |||
|
298 | # Look for response to ``hello`` command. Scan from the back so | |||
|
299 | # we don't misinterpret banner output as the command reply. | |||
|
300 | if l.startswith('capabilities:'): | |||
|
301 | caps.update(l[:-1].split(':')[1].split()) | |||
|
302 | break | |||
|
303 | elif protoname == wireprotoserver.SSHV2: | |||
|
304 | # We see a line with number of bytes to follow and then a value | |||
|
305 | # looking like ``capabilities: *``. | |||
|
306 | line = stdout.readline() | |||
|
307 | try: | |||
|
308 | valuelen = int(line) | |||
|
309 | except ValueError: | |||
|
310 | badresponse() | |||
|
311 | ||||
|
312 | capsline = stdout.read(valuelen) | |||
|
313 | if not capsline.startswith('capabilities: '): | |||
|
314 | badresponse() | |||
|
315 | ||||
|
316 | caps.update(capsline.split(':')[1].split()) | |||
|
317 | # Trailing newline. | |||
|
318 | stdout.read(1) | |||
|
319 | ||||
|
320 | # Error if we couldn't find capabilities, this means: | |||
247 | # |
|
321 | # | |
248 | # 1. Remote isn't a Mercurial server |
|
322 | # 1. Remote isn't a Mercurial server | |
249 | # 2. Remote is a <0.9.1 Mercurial server |
|
323 | # 2. Remote is a <0.9.1 Mercurial server | |
250 | # 3. Remote is a future Mercurial server that dropped ``hello`` |
|
324 | # 3. Remote is a future Mercurial server that dropped ``hello`` | |
251 | # support. |
|
325 | # and other attempted handshake mechanisms. | |
252 | if not caps: |
|
326 | if not caps: | |
253 | badresponse() |
|
327 | badresponse() | |
254 |
|
328 |
@@ -32,6 +32,12 b" HGTYPE = 'application/mercurial-0.1'" | |||||
32 | HGTYPE2 = 'application/mercurial-0.2' |
|
32 | HGTYPE2 = 'application/mercurial-0.2' | |
33 | HGERRTYPE = 'application/hg-error' |
|
33 | HGERRTYPE = 'application/hg-error' | |
34 |
|
34 | |||
|
35 | # Names of the SSH protocol implementations. | |||
|
36 | SSHV1 = 'ssh-v1' | |||
|
37 | # This is advertised over the wire. Incremental the counter at the end | |||
|
38 | # to reflect BC breakages. | |||
|
39 | SSHV2 = 'exp-ssh-v2-0001' | |||
|
40 | ||||
35 | class abstractserverproto(object): |
|
41 | class abstractserverproto(object): | |
36 | """abstract class that summarizes the protocol API |
|
42 | """abstract class that summarizes the protocol API | |
37 |
|
43 |
@@ -53,6 +53,35 b' class prehelloserver(wireprotoserver.ssh' | |||||
53 |
|
53 | |||
54 | super(prehelloserver, self).serve_forever() |
|
54 | super(prehelloserver, self).serve_forever() | |
55 |
|
55 | |||
|
56 | class upgradev2server(wireprotoserver.sshserver): | |||
|
57 | """Tests behavior for clients that issue upgrade to version 2.""" | |||
|
58 | def serve_forever(self): | |||
|
59 | name = wireprotoserver.SSHV2 | |||
|
60 | l = self._fin.readline() | |||
|
61 | assert l.startswith(b'upgrade ') | |||
|
62 | token, caps = l[:-1].split(b' ')[1:] | |||
|
63 | assert caps == b'proto=%s' % name | |||
|
64 | ||||
|
65 | # Filter hello and between requests. | |||
|
66 | l = self._fin.readline() | |||
|
67 | assert l == b'hello\n' | |||
|
68 | l = self._fin.readline() | |||
|
69 | assert l == b'between\n' | |||
|
70 | l = self._fin.readline() | |||
|
71 | assert l == 'pairs 81\n' | |||
|
72 | self._fin.read(81) | |||
|
73 | ||||
|
74 | # Send the upgrade response. | |||
|
75 | self._fout.write(b'upgraded %s %s\n' % (token, name)) | |||
|
76 | servercaps = wireproto.capabilities(self._repo, self) | |||
|
77 | rsp = b'capabilities: %s' % servercaps | |||
|
78 | self._fout.write(b'%d\n' % len(rsp)) | |||
|
79 | self._fout.write(rsp) | |||
|
80 | self._fout.write(b'\n') | |||
|
81 | self._fout.flush() | |||
|
82 | ||||
|
83 | super(upgradev2server, self).serve_forever() | |||
|
84 | ||||
56 | def performhandshake(orig, ui, stdin, stdout, stderr): |
|
85 | def performhandshake(orig, ui, stdin, stdout, stderr): | |
57 | """Wrapped version of sshpeer._performhandshake to send extra commands.""" |
|
86 | """Wrapped version of sshpeer._performhandshake to send extra commands.""" | |
58 | mode = ui.config(b'sshpeer', b'handshake-mode') |
|
87 | mode = ui.config(b'sshpeer', b'handshake-mode') | |
@@ -85,6 +114,8 b' def extsetup(ui):' | |||||
85 | wireprotoserver.sshserver = bannerserver |
|
114 | wireprotoserver.sshserver = bannerserver | |
86 | elif servermode == b'no-hello': |
|
115 | elif servermode == b'no-hello': | |
87 | wireprotoserver.sshserver = prehelloserver |
|
116 | wireprotoserver.sshserver = prehelloserver | |
|
117 | elif servermode == b'upgradev2': | |||
|
118 | wireprotoserver.sshserver = upgradev2server | |||
88 | elif servermode: |
|
119 | elif servermode: | |
89 | raise error.ProgrammingError(b'unknown server mode: %s' % servermode) |
|
120 | raise error.ProgrammingError(b'unknown server mode: %s' % servermode) | |
90 |
|
121 |
@@ -388,3 +388,107 b' And one with arguments' | |||||
388 | 0 |
|
388 | 0 | |
389 | 0 |
|
389 | 0 | |
390 | 0 |
|
390 | 0 | |
|
391 | ||||
|
392 | Send an upgrade request to a server that doesn't support that command | |||
|
393 | ||||
|
394 | $ hg -R server serve --stdio << EOF | |||
|
395 | > upgrade 2e82ab3f-9ce3-4b4e-8f8c-6fd1c0e9e23a proto=irrelevant1%2Cirrelevant2 | |||
|
396 | > hello | |||
|
397 | > between | |||
|
398 | > pairs 81 | |||
|
399 | > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 | |||
|
400 | > EOF | |||
|
401 | 0 | |||
|
402 | 384 | |||
|
403 | capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN | |||
|
404 | 1 | |||
|
405 | ||||
|
406 | ||||
|
407 | $ hg --config experimental.sshpeer.advertise-v2=true --debug debugpeer ssh://user@dummy/server | |||
|
408 | running * "*/tests/dummyssh" 'user@dummy' 'hg -R server serve --stdio' (glob) | |||
|
409 | sending upgrade request: * proto=exp-ssh-v2-0001 (glob) | |||
|
410 | devel-peer-request: hello | |||
|
411 | sending hello command | |||
|
412 | devel-peer-request: between | |||
|
413 | devel-peer-request: pairs: 81 bytes | |||
|
414 | sending between command | |||
|
415 | remote: 0 | |||
|
416 | remote: 384 | |||
|
417 | remote: capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN | |||
|
418 | remote: 1 | |||
|
419 | url: ssh://user@dummy/server | |||
|
420 | local: no | |||
|
421 | pushable: yes | |||
|
422 | ||||
|
423 | Send an upgrade request to a server that supports upgrade | |||
|
424 | ||||
|
425 | $ SSHSERVERMODE=upgradev2 hg -R server serve --stdio << EOF | |||
|
426 | > upgrade this-is-some-token proto=exp-ssh-v2-0001 | |||
|
427 | > hello | |||
|
428 | > between | |||
|
429 | > pairs 81 | |||
|
430 | > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 | |||
|
431 | > EOF | |||
|
432 | upgraded this-is-some-token exp-ssh-v2-0001 | |||
|
433 | 383 | |||
|
434 | capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN | |||
|
435 | ||||
|
436 | $ SSHSERVERMODE=upgradev2 hg --config experimental.sshpeer.advertise-v2=true --debug debugpeer ssh://user@dummy/server | |||
|
437 | running * "*/tests/dummyssh" 'user@dummy' 'hg -R server serve --stdio' (glob) | |||
|
438 | sending upgrade request: * proto=exp-ssh-v2-0001 (glob) | |||
|
439 | devel-peer-request: hello | |||
|
440 | sending hello command | |||
|
441 | devel-peer-request: between | |||
|
442 | devel-peer-request: pairs: 81 bytes | |||
|
443 | sending between command | |||
|
444 | protocol upgraded to exp-ssh-v2-0001 | |||
|
445 | url: ssh://user@dummy/server | |||
|
446 | local: no | |||
|
447 | pushable: yes | |||
|
448 | ||||
|
449 | Verify the peer has capabilities | |||
|
450 | ||||
|
451 | $ SSHSERVERMODE=upgradev2 hg --config experimental.sshpeer.advertise-v2=true --debug debugcapabilities ssh://user@dummy/server | |||
|
452 | running * "*/tests/dummyssh" 'user@dummy' 'hg -R server serve --stdio' (glob) | |||
|
453 | sending upgrade request: * proto=exp-ssh-v2-0001 (glob) | |||
|
454 | devel-peer-request: hello | |||
|
455 | sending hello command | |||
|
456 | devel-peer-request: between | |||
|
457 | devel-peer-request: pairs: 81 bytes | |||
|
458 | sending between command | |||
|
459 | protocol upgraded to exp-ssh-v2-0001 | |||
|
460 | Main capabilities: | |||
|
461 | batch | |||
|
462 | branchmap | |||
|
463 | $USUAL_BUNDLE2_CAPS_SERVER$ | |||
|
464 | changegroupsubset | |||
|
465 | getbundle | |||
|
466 | known | |||
|
467 | lookup | |||
|
468 | pushkey | |||
|
469 | streamreqs=generaldelta,revlogv1 | |||
|
470 | unbundle=HG10GZ,HG10BZ,HG10UN | |||
|
471 | unbundlehash | |||
|
472 | Bundle2 capabilities: | |||
|
473 | HG20 | |||
|
474 | bookmarks | |||
|
475 | changegroup | |||
|
476 | 01 | |||
|
477 | 02 | |||
|
478 | digests | |||
|
479 | md5 | |||
|
480 | sha1 | |||
|
481 | sha512 | |||
|
482 | error | |||
|
483 | abort | |||
|
484 | unsupportedcontent | |||
|
485 | pushraced | |||
|
486 | pushkey | |||
|
487 | hgtagsfnodes | |||
|
488 | listkeys | |||
|
489 | phases | |||
|
490 | heads | |||
|
491 | pushkey | |||
|
492 | remote-changegroup | |||
|
493 | http | |||
|
494 | https |
General Comments 0
You need to be logged in to leave comments.
Login now