This page documents a proposal to add versioning to the WireProtocol and to deploy a new wire protocol version that supports additional features.
The immediate goal of this proposal is to add bi-directional exchange of arbitrary key-value metadata. The intended use case is to allow extensions to extend existing commands in new and creative ways. But, this functionality may also be used by Mercurial core and core-shipped extensions to add features to Mercurial in the future. For example, this feature could facilitate the transmission of messages for client-side display on every command - not just commands that support it today.
A capability will be exposed stating which wire protocol versions are supported. e.g.
At the beginning of interaction with a remote, the client will perform a capabilities command like it has done for years. (Could this be done in hello instead?).
If the remote does not expose the protocols capability, the client will assume wireproto version 1 is the only version supported.
If the remote exposes the protocols capability, the client may select any supported version for subsequent commands issued during that session. Selecting the highest mutually-supported version is highly recommended.
Versioned SSH Wire Protocol
The SSH peer will need to identify the version of the wire protocol in use. We have a number of options here.
Commands are prefixed with a version identifier
In this solution, each command string is prefixed by a version identifier. The version identifier is likely something binary so it can't be confused for a command name. e.g.
Here, the the version identifier is \x01\x02 and the command is getbundle. \x01 says a version identifier will follow in the next byte. \x02 is the protocol version. In this case, version 2. The prefix could be any byte sequence we want.
In this solution, command receivers will examine the first few bytes of every supposed command line and look for the special version identifying bytes. If found, it will interpret the remaining payload using the requested wire protocol version. If not found, it will assume version 1 (the original) wire protocol is in use. Therefore, this method is backwards compatible with old clients.
Client issues version switch command
In this solution, the client will issue a special command indicating an upgrade of the current channel to a new wire protocol version. e.g.
All subsequent commands will use the specified version of the wire protocol.
Clients should not send this command unless both they and the remote support the specified version (via capabilities negotiation). If this command is not received, the remote will assume version 1 (the original) wire protocol is in use.
Wire Protocol Version 2
Wire protocol version 2 allows the bi-directional transfer of arbitrary key-value pairs between peers. These key-value pairs supplement the existing key-value arguments that are facilitated through the existing wire protocol.
The reason a new wire protocol version with a seemingly redundant mechanism for transmitting key-value pairs is present is backwards compatibility. The API for commands must remain backwards compatible and peers or clients receiving unknown commands may error. By making version control 2 advertised and opt-in, clients should not send data to the server that would be unrecognized.
SSH Wire protocol 2 looks very similar to version 1. Here is a request for the lookup command sending two extra keys - extra1 and extra2.
lookup extra-begin extra1 3 foo extra2 4 bar1 extra-end key 3 tip
It starts with the command name. Next, we have a well-defined marker extra-begin. Following is named arguments in the version 1 protocol format of defining arguments. We have the key name followed by the integer length followed by the value on a new line. The end of the extra arguments are denoted by extra-end. What follows is the original version 1 wire protocol arguments.