The Mercurial wire protocol is a request-response based protocol with multiple wire representations. Each request is modeled as a command name, a dictionary of arguments, and optional raw input. Command arguments and their types are intrinsic properties of commands. So is the response type of the command. This means clients can't always send arbitrary arguments to servers and servers can't return multiple response types. The protocol is synchronous and does not support multiplexing (concurrent commands). Transport Protocols =================== HTTP Transport -------------- Commands are issued as HTTP/1.0 or HTTP/1.1 requests. Commands are sent to the base URL of the repository with the command name sent in the ``cmd`` query string parameter. e.g. ``https://example.com/repo?cmd=capabilities``. The HTTP method is ``GET`` or ``POST`` depending on the command and whether there is a request body. Command arguments can be sent multiple ways. The simplest is part of the URL query string using ``x-www-form-urlencoded`` encoding (see Python's ``urllib.urlencode()``. However, many servers impose length limitations on the URL. So this mechanism is typically only used if the server doesn't support other mechanisms. If the server supports the ``httpheader`` capability, command arguments can be sent in HTTP request headers named ``X-HgArg-`` where ```` is an integer starting at 1. A ``x-www-form-urlencoded`` representation of the arguments is obtained. This full string is then split into chunks and sent in numbered ``X-HgArg-`` headers. The maximum length of each HTTP header is defined by the server in the ``httpheader`` capability value, which defaults to ``1024``. The server reassembles the encoded arguments string by concatenating the ``X-HgArg-`` headers then URL decodes them into a dictionary. The list of ``X-HgArg-`` headers should be added to the ``Vary`` request header to instruct caches to take these headers into consideration when caching requests. If the server supports the ``httppostargs`` capability, the client may send command arguments in the HTTP request body as part of an HTTP POST request. The command arguments will be URL encoded just like they would for sending them via HTTP headers. However, no splitting is performed: the raw arguments are included in the HTTP request body. The client sends a ``X-HgArgs-Post`` header with the string length of the encoded arguments data. Additional data may be included in the HTTP request body immediately following the argument data. The offset of the non-argument data is defined by the ``X-HgArgs-Post`` header. The ``X-HgArgs-Post`` header is not required if there is no argument data. Additional command data can be sent as part of the HTTP request body. The default ``Content-Type`` when sending data is ``application/mercurial-0.1``. A ``Content-Length`` header is currently always sent. Example HTTP requests:: GET /repo?cmd=capabilities X-HgArg-1: foo=bar&baz=hello%20world The ``Content-Type`` HTTP response header identifies the response as coming from Mercurial and can also be used to signal an error has occurred. The ``application/mercurial-0.1`` media type indicates a generic Mercurial response. It matches the media type sent by the client. The ``application/hg-error`` media type indicates a generic error occurred. The content of the HTTP response body typically holds text describing the error. The ``application/hg-changegroup`` media type indicates a changegroup response type. Clients also accept the ``text/plain`` media type. All other media types should cause the client to error. Clients should issue a ``User-Agent`` request header that identifies the client. The server should not use the ``User-Agent`` for feature detection. A command returning a ``string`` response issues the ``application/mercurial-0.1`` media type and the HTTP response body contains the raw string value. A ``Content-Length`` header is typically issued. A command returning a ``stream`` response issues the ``application/mercurial-0.1`` media type and the HTTP response is typically using *chunked transfer* (``Transfer-Encoding: chunked``). SSH Transport ============= The SSH transport is a custom text-based protocol suitable for use over any bi-directional stream transport. It is most commonly used with SSH. A SSH transport server can be started with ``hg serve --stdio``. The stdin, stderr, and stdout file descriptors of the started process are used to exchange data. When Mercurial connects to a remote server over SSH, it actually starts a ``hg serve --stdio`` process on the remote server. Commands are issued by sending the command name followed by a trailing newline ``\n`` to the server. e.g. ``capabilities\n``. Command arguments are sent in the following format:: \n That is, the argument string name followed by a space followed by the integer length of the value (expressed as a string) followed by a newline (``\n``) followed by the raw argument value. Dictionary arguments are encoded differently:: <# elements>\n \n \n ... Non-argument data is sent immediately after the final argument value. It is encoded in chunks:: \n Each command declares a list of supported arguments and their types. If a client sends an unknown argument to the server, the server should abort immediately. The special argument ``*`` in a command's definition indicates that all argument names are allowed. The definition of supported arguments and types is initially made when a new command is implemented. The client and server must initially independently agree on the arguments and their types. This initial set of arguments can be supplemented through the presence of *capabilities* advertised by the server. Each command has a defined expected response type. A ``string`` response type is a length framed value. The response consists of the string encoded integer length of a value followed by a newline (``\n``) followed by the value. Empty values are allowed (and are represented as ``0\n``). A ``stream`` response type consists of raw bytes of data. There is no framing. A generic error response type is also supported. It consists of a an error message written to ``stderr`` followed by ``\n-\n``. In addition, ``\n`` is written to ``stdout``. If the server receives an unknown command, it will send an empty ``string`` response. The server terminates if it receives an empty command (a ``\n`` character). Capabilities ============ Servers advertise supported wire protocol features. This allows clients to probe for server features before blindly calling a command or passing a specific argument. The server's features are exposed via a *capabilities* string. This is a space-delimited string of tokens/features. Some features are single words like ``lookup`` or ``batch``. Others are complicated key-value pairs advertising sub-features. e.g. ``httpheader=2048``. When complex, non-word values are used, each feature name can define its own encoding of sub-values. Comma-delimited and ``x-www-form-urlencoded`` values are common. The following document capabilities defined by the canonical Mercurial server implementation. batch ----- Whether the server supports the ``batch`` command. This capability/command was introduced in Mercurial 1.9 (released July 2011). branchmap --------- Whether the server supports the ``branchmap`` command. This capability/command was introduced in Mercurial 1.3 (released July 2009). bundle2-exp ----------- Precursor to ``bundle2`` capability that was used before bundle2 was a stable feature. This capability was introduced in Mercurial 3.0 behind an experimental flag. This capability should not be observed in the wild. bundle2 ------- Indicates whether the server supports the ``bundle2`` data exchange format. The value of the capability is a URL quoted, newline (``\n``) delimited list of keys or key-value pairs. A key is simply a URL encoded string. A key-value pair is a URL encoded key separated from a URL encoded value by an ``=``. If the value is a list, elements are delimited by a ``,`` after URL encoding. For example, say we have the values:: {'HG20': [], 'changegroup': ['01', '02'], 'digests': ['sha1', 'sha512']} We would first construct a string:: HG20\nchangegroup=01,02\ndigests=sha1,sha512 We would then URL quote this string:: HG20%0Achangegroup%3D01%2C02%0Adigests%3Dsha1%2Csha512 This capability was introduced in Mercurial 3.4 (released May 2015). changegroupsubset ----------------- Whether the server supports the ``changegroupsubset`` command. This capability was introduced in Mercurial 0.9.2 (released December 2006). This capability was introduced at the same time as the ``lookup`` capability/command. getbundle --------- Whether the server supports the ``getbundle`` command. This capability was introduced in Mercurial 1.9 (released July 2011). httpheader ---------- Whether the server supports receiving command arguments via HTTP request headers. The value of the capability is an integer describing the max header length that clients should send. Clients should ignore any content after a comma in the value, as this is reserved for future use. This capability was introduced in Mercurial 1.9 (released July 2011). httppostargs ------------ **Experimental** Indicates that the server supports and prefers clients send command arguments via a HTTP POST request as part of the request body. This capability was introduced in Mercurial 3.8 (released May 2016). known ----- Whether the server supports the ``known`` command. This capability/command was introduced in Mercurial 1.9 (released July 2011). lookup ------ Whether the server supports the ``lookup`` command. This capability was introduced in Mercurial 0.9.2 (released December 2006). This capability was introduced at the same time as the ``changegroupsubset`` capability/command. pushkey ------- Whether the server supports the ``pushkey`` and ``listkeys`` commands. This capability was introduced in Mercurial 1.6 (released July 2010). standardbundle -------------- **Unsupported** This capability was introduced during the Mercurial 0.9.2 development cycle in 2006. It was never present in a release, as it was replaced by the ``unbundle`` capability. This capability should not be encountered in the wild. stream-preferred ---------------- If present the server prefers that clients clone using the streaming clone protocol (``hg clone --uncompressed``) rather than the standard changegroup/bundle based protocol. This capability was introduced in Mercurial 2.2 (released May 2012). streamreqs ---------- Indicates whether the server supports *streaming clones* and the *requirements* that clients must support to receive it. If present, the server supports the ``stream_out`` command, which transmits raw revlogs from the repository instead of changegroups. This provides a faster cloning mechanism at the expense of more bandwidth used. The value of this capability is a comma-delimited list of repo format *requirements*. These are requirements that impact the reading of data in the ``.hg/store`` directory. An example value is ``streamreqs=generaldelta,revlogv1`` indicating the server repo requires the ``revlogv1`` and ``generaldelta`` requirements. If the only format requirement is ``revlogv1``, the server may expose the ``stream`` capability instead of the ``streamreqs`` capability. This capability was introduced in Mercurial 1.7 (released November 2010). stream ------ Whether the server supports *streaming clones* from ``revlogv1`` repos. If present, the server supports the ``stream_out`` command, which transmits raw revlogs from the repository instead of changegroups. This provides a faster cloning mechanism at the expense of more bandwidth used. This capability was introduced in Mercurial 0.9.1 (released July 2006). When initially introduced, the value of the capability was the numeric revlog revision. e.g. ``stream=1``. This indicates the changegroup is using ``revlogv1``. This simple integer value wasn't powerful enough, so the ``streamreqs`` capability was invented to handle cases where the repo requirements have more than just ``revlogv1``. Newer servers omit the ``=1`` since it was the only value supported and the value of ``1`` can be implied by clients. unbundlehash ------------ Whether the ``unbundle`` commands supports receiving a hash of all the heads instead of a list. For more, see the documentation for the ``unbundle`` command. This capability was introduced in Mercurial 1.9 (released July 2011). unbundle -------- Whether the server supports pushing via the ``unbundle`` command. This capability/command has been present since Mercurial 0.9.1 (released July 2006). Mercurial 0.9.2 (released December 2006) added values to the capability indicating which bundle types the server supports receiving. This value is a comma-delimited list. e.g. ``HG10GZ,HG10BZ,HG10UN``. The order of values reflects the priority/preference of that type, where the first value is the most preferred type.