[PATCH 1 of 3] bundle2: add separate handling for error part creation
Siddharth Agarwal
sid0 at fb.com
Tue Apr 4 23:43:19 UTC 2017
# HG changeset patch
# User Siddharth Agarwal <sid0 at fb.com>
# Date 1491348154 25200
# Tue Apr 04 16:22:34 2017 -0700
# Node ID 5c84da513a5ff56a973a89631f266c6fcf9b18cd
# Parent 04ec317b81280c189fcea33a05c8cbbac3c186b1
bundle2: add separate handling for error part creation
This will be used in upcoming diffs to handle error parts.
See the included docstrings for why this is necessary.
diff --git a/mercurial/bundle2.py b/mercurial/bundle2.py
--- a/mercurial/bundle2.py
+++ b/mercurial/bundle2.py
@@ -177,6 +177,7 @@ urlreq = util.urlreq
_fpartid = '>I'
_fpayloadsize = '>i'
_fpartparamcount = '>BB'
+_ferrorlongparamsize = '>I'
preferedchunksize = 4096
@@ -557,6 +558,20 @@ class bundle20(object):
self.addpart(part)
return part
+ def newerrorpart(self, typeid, *args, **kwargs):
+ """create a new error part and add it to the containers
+
+ This is only required for the following error parts that are recognized
+ by Mercurial 4.1 or lower.
+ - error:abort
+ - error:pushraced
+ - error:unsupportedcontent
+
+ See bundleerrorpart for more."""
+ part = bundleerrorpart(typeid, *args, **kwargs)
+ self.addpart(part)
+ return part
+
# methods used to generate the bundle2 stream
def getchunks(self):
if self.ui.debugflag:
@@ -1026,6 +1041,54 @@ class bundlepart(object):
elif len(self.data):
yield self.data
+class bundleerrorpart(bundlepart):
+ """
+ This is only required for the following error parts that are recognized
+ by Mercurial versions below 4.2.
+ - error:abort
+ - error:pushraced
+ - error:unsupportedcontent
+
+ In Mercurial below 4.2, error messages for these parts were stored as
+ part parameters. Since parameter sizes can be 255 at most, this meant that
+ error messages longer than 255 bytes would crash the Mercurial server.
+
+ To avoid this issue while still retaining backwards compatibility with older
+ versions of Mercurial, this class of parts:
+ * truncates long params to 255 bytes
+ * adds such params to the payload instead.
+
+ Any newer error parts should instead:
+ - use newpart
+ - take care not to set up any params with potentially unbounded length
+ - send the unbounded param(s) (e.g. error message) as part of the
+ payload
+ """
+ def __init__(self, *args, **kwargs):
+ super(bundleerrorpart, self).__init__(*args, **kwargs)
+ self._errordata = []
+ self.addparam('longparams', 'payload', mandatory=False)
+
+ def addlongparam(self, name, value='', mandatory=True):
+ vparam = value
+ if len(value) > 255:
+ # truncate value so that it doesn't crash
+ vparam = value[:252] + '...'
+ self.addparam(name, vparam, mandatory=mandatory)
+ # encode the full error message as
+ # (len(name), name, len(value), value)
+ # mandatory is enforced by the param
+ data = [struct.pack(_ferrorlongparamsize, len(name)), name,
+ struct.pack(_ferrorlongparamsize, len(value)), value]
+ self._errordata.append(''.join(data))
+
+ def getchunks(self, ui):
+ # data = number of long params + all the params
+ numparams = len(self._errordata)
+ errordata = ([struct.pack(_ferrorlongparamsize, numparams)] +
+ self._errordata)
+ self._data = ''.join(errordata)
+ return super(bundleerrorpart, self).getchunks(ui)
flaginterrupt = -1
More information about the Mercurial-devel
mailing list