Patchwork [10,of,11] httppeer: advertise and support application/mercurial-0.2

login
register
mail settings
Submitter Gregory Szorc
Date Nov. 20, 2016, 10:23 p.m.
Message ID <bae72dfc96ca2eb58c14.1479680627@ubuntu-vm-main>
Download mbox | patch
Permalink /patch/17660/
State Accepted
Headers show

Comments

Gregory Szorc - Nov. 20, 2016, 10:23 p.m.
# HG changeset patch
# User Gregory Szorc <gregory.szorc@gmail.com>
# Date 1479679561 28800
#      Sun Nov 20 14:06:01 2016 -0800
# Node ID bae72dfc96ca2eb58c1484148a8585c6b25cc0b6
# Parent  f3f2bb7d66a45f16856ad890a8892b3dbafa480e
httppeer: advertise and support application/mercurial-0.2

Now that servers expose a capability indicating they support
compression, clients can key off this to say they support responses
that are compressed with various compression formats.

After this commit, the HTTP wire protocol client now sends an
"Accept" request header indicating it supports the
"application/mercurial-0.2" media type. Within that header, it
indicates the compression formats it supports receiving.

This commit also implements support for handling
"application/mercurial-0.2" responses. It simply reads the
first 2 bytes of the response to identify the compression engine
then routes the remainder of the response to the appropriate
decompressor.

Surprisingly, no tests needed updating as a result of this change.
That points to an obvious gap in our test coverage. This will be
addressed in a subsequent commit once server support is in place
(it is hard to test without server support).

Patch

diff --git a/mercurial/httppeer.py b/mercurial/httppeer.py
--- a/mercurial/httppeer.py
+++ b/mercurial/httppeer.py
@@ -159,6 +159,28 @@  class httppeer(wireproto.wirepeer):
         if data is not None:
             self.ui.debug("sending %s bytes\n" % size)
             req.add_unredirected_header('Content-Length', '%d' % size)
+
+        # Tell the server we accept application/mercurial-0.2 and multiple
+        # compression formats if the server is capable of emitting those
+        # payloads.
+        if self.caps is not None and self.capable('compression'):
+            comps = [e.wireprotosupport()[0] for e in
+                     util.compengines.supportedwireengines('client',
+                                                           onlyavailable=True)]
+
+            # We /could/ compare supported compression formats and take
+            # action if nothing is mutually supported. However, servers
+            # supporting the "compression" capability are required to support
+            # "application/mercurial-0.2." Furthermore, sending the list of
+            # supported compression formats allows server operators to make data
+            # driven decisions about which formats they should support.
+            req.headers['Accept'] = ', '.join([
+                # Use of 0.5 here is arbitrary. It is present strictly for
+                # adherence to the HTTP specification so there isn't
+                # ambiguity about media type preference.
+                'application/mercurial-0.1;q=0.5',
+                'application/mercurial-0.2;comp="%s"' % ' '.join(comps),
+            ])
         try:
             resp = self.urlopener.open(req)
         except urlerr.httperror as inst:
@@ -206,7 +228,17 @@  class httppeer(wireproto.wirepeer):
             except ValueError:
                 raise error.RepoError(_("'%s' sent a broken Content-Type "
                                         "header (%s)") % (safeurl, proto))
-            if version_info > (0, 1):
+
+            if version_info == (0, 1):
+                if _compressible:
+                    return decompressresponse(resp, util.compengines['zlib'])
+                return resp
+            elif version_info == (0, 2):
+                # application/mercurial-0.2 always identifies the compression
+                # engine in the payload header.
+                engine = util.compengines.forwiretype(resp.read(2))
+                return decompressresponse(resp, engine)
+            else:
                 raise error.RepoError(_("'%s' uses newer protocol %s") %
                                       (safeurl, version))
 
diff --git a/mercurial/url.py b/mercurial/url.py
--- a/mercurial/url.py
+++ b/mercurial/url.py
@@ -475,6 +475,11 @@  def opener(ui, authinfo=None):
     # user agent they deem appropriate.
     agent = 'mercurial/proto-1.0 (Mercurial %s)' % util.version()
     opener.addheaders = [('User-agent', agent)]
+
+    # This header should only be needed by wire protocol requests. But it has
+    # been sent on all requests since forever. We keep sending it for backwards
+    # compatibility reasons. The wire protocol client may override this header
+    # to add support for additional media types.
     opener.addheaders.append(('Accept', 'application/mercurial-0.1'))
     return opener