# HG changeset patch # User Siddharth Agarwal <s...@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 _______________________________________________ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel