wireprotov2: define semantics for content redirects
authorGregory Szorc <gregory.szorc@gmail.com>
Wed, 26 Sep 2018 18:02:06 -0700
changeset 40022 33eb670e2834
parent 40021 c537144fdbef
child 40023 10cf8b116dd8
wireprotov2: define semantics for content redirects When I implemented the clonebundles feature and deployed it on hg.mozilla.org using Amazon S3 as a content server, server-side CPU and bandwidth usage dropped off a cliff and a ton of server scaling headaches went away pretty much the instant clients with support for clonebundles were rolled out to Firefox CI. An obvious takeaway from that experience was that offloading server load to scalable file servers - potentially backed by a CDN - is a really good idea. Another takeaway was that Mercurial's wire protocol wasn't in a good position to support data offload generally. In wire protocol version 1, there isn't a mechanism in the protocol to say "grab the data from over here instead." For HTTP, we could teach the client to follow HTTP redirects. Or we could invent a media type that encoded redirects inline. But for SSH, we were pretty much out of luck because that protocol wasn't very flexible. Wire protocol version 2 offers the opportunity to do something better. The recent generic server-side content caching layer in the wire protocol version 2 server demonstrated that it is possible to have drop-in caching of responses to command requests. This by itself adds tons of value and already makes the built-in server much more scalable. But I don't want to stop there. The existing server-side caching implementation has a big weakness: it requires the server to send data to the client. This means that the Mercurial server is potentially sending gigabytes of data to thousands of clients. This is problematic because compared to scaling static file servers, scaling dynamic servers is *hard*. A solution to this is to "offload" serving of content to something that isn't the Mercurial server. By offloading content serving, you turn the Mercurial server from a centralized monolithic service to a distributed mostly-indexing service. Assuming high rates of content offload, this should drastically reduce the total work performed by the Mercurial server, both in terms of CPU and data transfer. This will make Mercurial servers vastly easier to scale. This commit defines the semantics for "content redirects" in wire protocol version 2. Essentially: * Servers advertise the set of locations a response could be served from. * When making requests, clients advertise the set of locations they are willing to fetch content from. * Servers can then replace the inline response with one that says "get the response from over here instead." This feature - when fully implemented - will allow extending the server-side caching layer to facilitate such things as integrating your server-side cache with a scalable blob store (such as S3 or a CDN) and offloading most data transfer to that external service. This feature could also be leveraged for load balancing. e.g. requests could come into a central server and then get redirected to an available mirror depending on server availability or locality. There's tons of potential :) Differential Revision: https://phab.mercurial-scm.org/D4774
mercurial/help/internals/wireprotocolrpc.txt
mercurial/help/internals/wireprotocolv2.txt
--- a/mercurial/help/internals/wireprotocolrpc.txt	Wed Sep 26 17:16:56 2018 -0700
+++ b/mercurial/help/internals/wireprotocolrpc.txt	Wed Sep 26 18:02:06 2018 -0700
@@ -115,6 +115,22 @@
    Each command defines its own set of argument names and their expected
    types.
 
+redirect (optional)
+   (map) Advertises client support for following response *redirects*.
+
+   This map has the following bytestring keys:
+
+   targets
+      (array of bytestring) List of named redirect targets supported by
+      this client. The names come from the targets advertised by the
+      server's *capabilities* message.
+
+   hashes
+      (array of bytestring) List of preferred hashing algorithms that can
+      be used for content integrity verification.
+
+   See the *Content Redirects* section below for more on content redirects.
+
 This frame type MUST ONLY be sent from clients to servers: it is illegal
 for a server to send this frame to a client.
 
@@ -506,6 +522,9 @@
    error
       There was an error processing the command. More details about the
       error are encoded in the ``error`` key.
+   redirect
+      The response for this command is available elsewhere. Details on
+      where are in the ``location`` key.
 
 error (optional)
    A map containing information about an encountered error. The map has the
@@ -515,5 +534,116 @@
       (array of maps) A message describing the error. The message uses the
       same format as those in the ``Human Output Side-Channel`` frame.
 
+location (optional)
+   (map) Presence indicates that a *content redirect* has occurred. The map
+   provides the external location of the content.
+
+   This map contains the following bytestring keys:
+
+   url
+      (bytestring) URL from which this content may be requested.
+
+   mediatype
+      (bytestring) The media type for the fetched content. e.g.
+      ``application/mercurial-*``.
+
+      In some transports, this value is also advertised by the transport.
+      e.g. as the ``Content-Type`` HTTP header.
+
+   size (optional)
+      (unsigned integer) Total size of remote object in bytes. This is
+      the raw size of the entity that will be fetched, minus any
+      non-Mercurial protocol encoding (e.g. HTTP content or transfer
+      encoding.)
+
+   fullhashes (optional)
+      (array of arrays) Content hashes for the entire payload. Each entry
+      is an array of bytestrings containing the hash name and the hash value.
+
+   fullhashseed (optional)
+      (bytestring) Optional seed value to feed into hasher for full content
+      hash verification.
+
+   serverdercerts (optional)
+      (array of bytestring) DER encoded x509 certificates for the server. When
+      defined, clients MAY validate that the x509 certificate on the target
+      server exactly matches the certificate used here.
+
+   servercadercerts (optional)
+      (array of bytestring) DER encoded x509 certificates for the certificate
+      authority of the target server. When defined, clients MAY validate that
+      the x509 on the target server was signed by CA certificate in this set.
+
+   # TODO support for giving client an x509 certificate pair to be used as a
+   # client certificate.
+
+   # TODO support common authentication mechanisms (e.g. HTTP basic/digest
+   # auth).
+
+   # TODO support custom authentication mechanisms. This likely requires
+   # server to advertise required auth mechanism so client can filter.
+
+   # TODO support chained hashes. e.g. hash for each 1MB segment so client
+   # can iteratively validate data without having to consume all of it first.
+
 TODO formalize when error frames can be seen and how errors can be
 recognized midway through a command response.
+
+Content Redirects
+=================
+
+Servers have the ability to respond to ANY command request with a
+*redirect* to another location. Such a response is referred to as a *redirect
+response*. (This feature is conceptually similar to HTTP redirects, but is
+more powerful.)
+
+A *redirect response* MUST ONLY be issued if the client advertises support
+for a redirect *target*.
+
+A *redirect response* MUST NOT be issued unless the client advertises support
+for one.
+
+Clients advertise support for *redirect responses* after looking at the server's
+*capabilities* data, which is fetched during initial server connection
+handshake. The server's capabilities data advertises named *targets* for
+potential redirects.
+
+Each target is described by a protocol name, connection and protocol features,
+etc. The server also advertises target-agnostic redirect settings, such as
+which hash algorithms are supported for content integrity checking. (See
+the documentation for the *capabilities* command for more.)
+
+Clients examine the set of advertised redirect targets for compatibility.
+When sending a command request, the client advertises the set of redirect
+target names it is willing to follow, along with some other settings influencing
+behavior.
+
+For example, say the server is advertising a ``cdn`` redirect target that
+requires SNI and TLS 1.2. If the client supports those features, it will
+send command requests stating that the ``cdn`` target is acceptable to use.
+But if the client doesn't support SNI or TLS 1.2 (or maybe it encountered an
+error using this target from a previous request), then it omits this target
+name.
+
+If the client advertises support for a redirect target, the server MAY
+substitute the normal, inline response data for a *redirect response* -
+one where the initial CBOR map has a ``status`` key with value ``redirect``.
+
+The *redirect response* at a minimum advertises the URL where the response
+can be retrieved.
+
+The *redirect response* MAY also advertise additional details about that
+content and how to retrieve it. Notably, the response may contain the
+x509 public certificates for the server being redirected to or the
+certificate authority that signed that server's certificate. Unless the
+client has existing settings that offer stronger trust validation than what
+the server advertises, the client SHOULD use the server-provided certificates
+when validating the connection to the remote server in place of any default
+connection verification checks. This is because certificates coming from
+the server SHOULD establish a stronger chain of trust than what the default
+certification validation mechanism in most environments provides. (By default,
+certificate validation ensures the signer of the cert chains up to a set of
+trusted root certificates. And if an explicit certificate or CA certificate
+is presented, that greadly reduces the set of certificates that will be
+recognized as valid, thus reducing the potential for a "bad" certificate
+to be used and trusted.)
--- a/mercurial/help/internals/wireprotocolv2.txt	Wed Sep 26 17:16:56 2018 -0700
+++ b/mercurial/help/internals/wireprotocolv2.txt	Wed Sep 26 18:02:06 2018 -0700
@@ -111,6 +111,38 @@
    requirements can be used to determine whether a client can read a
    *raw* copy of file data available.
 
+redirect
+   A map declaring potential *content redirects* that may be used by this
+   server. Contains the following bytestring keys:
+
+   targets
+      (array of maps) Potential redirect targets. Values are maps describing
+      this target in more detail. Each map has the following bytestring keys:
+
+      name
+         (bytestring) Identifier for this target. The identifier will be used
+         by clients to uniquely identify this target.
+
+      protocol
+         (bytestring) High-level network protocol. Values can be
+         ``http``, ```https``, ``ssh``, etc.
+
+      uris
+          (array of bytestrings) Representative URIs for this target.
+
+      snirequired (optional)
+          (boolean) Indicates whether Server Name Indication is required
+          to use this target. Defaults to False.
+
+      tlsversions (optional)
+          (array of bytestring) Indicates which TLS versions are supported by
+          this target. Values are ``1.1``, ``1.2``, ``1.3``, etc.
+
+   hashes
+      (array of bytestring) Indicates support for hashing algorithms that are
+      used to ensure content integrity. Values include ``sha1``, ``sha256``,
+      etc.
+
 changesetdata
 -------------