Parse partial length headers correctly.

This commit is contained in:
J08nY
2017-08-04 17:14:17 +02:00
parent e183c68fbf
commit 00d9217f19
2 changed files with 33 additions and 27 deletions

View File

@@ -367,30 +367,39 @@ class Header(Field):
@length.register(bytearray) @length.register(bytearray)
def length_bin(self, val): def length_bin(self, val):
def _new_len(b): def _new_len(b):
fo = b[0] def _parse_len(a, offset=0):
# returns (the parsed length, size of length field, whether the length was of partial type)
fo = a[offset]
if 192 > fo: if 192 > fo:
self._len = self.bytes_to_int(b[:1]) return (self.bytes_to_int(a[offset:offset + 1]), 1, False)
del b[:1]
elif 224 > fo: # >= 192 is implied elif 224 > fo: # >= 192 is implied
dlen = self.bytes_to_int(b[:2]) dlen = self.bytes_to_int(b[offset:offset + 2])
self._len = ((dlen - (192 << 8)) & 0xFF00) + ((dlen & 0xFF) + 192) return (((dlen - (192 << 8)) & 0xFF00) + ((dlen & 0xFF) + 192), 2, False)
del b[:2]
elif 255 > fo: # pragma: no cover elif 255 > fo: # >= 224 is implied
# not testable until partial body lengths actually work # this is a partial-length header
# >= 224 is implied return (1 << (fo & 0x1f), 1, True)
# this is a partial-length header
self._partial = True
self._len = 1 << (fo & 0x1f)
elif 255 == fo: elif 255 == fo:
self._len = self.bytes_to_int(b[1:5]) return (self.bytes_to_int(b[offset + 1:offset + 5]), 5, False)
del b[:5]
else: # pragma: no cover else: # pragma: no cover
raise ValueError("Malformed length: 0x{:02x}".format(fo)) raise ValueError("Malformed length: 0x{:02x}".format(fo))
part_len, size, partial = _parse_len(b)
del b[:size]
if partial:
total = part_len
while partial:
part_len, size, partial = _parse_len(b, total)
del b[total:total+size]
total += part_len
self._len = total
else:
self._len = part_len
def _old_len(b): def _old_len(b):
if self.llen > 0: if self.llen > 0:

View File

@@ -40,16 +40,12 @@ def binload(f):
return buf return buf
skip_files = {'tests/testdata/packets/{:s}'.format(pkt) for pkt in ['11.partial.literal']}
pktfiles = sorted(glob.glob('tests/testdata/packets/[0-9]*')) pktfiles = sorted(glob.glob('tests/testdata/packets/[0-9]*'))
class TestPacket(object): class TestPacket(object):
@pytest.mark.parametrize('packet', pktfiles, ids=[os.path.basename(f) for f in pktfiles]) @pytest.mark.parametrize('packet', pktfiles, ids=[os.path.basename(f) for f in pktfiles])
def test_load(self, packet): def test_load(self, packet):
if packet in skip_files:
pytest.skip("not implemented yet")
b = binload(packet) + _trailer b = binload(packet) + _trailer
_b = b[:] _b = b[:]
p = Packet(_b) p = Packet(_b)
@@ -59,11 +55,12 @@ class TestPacket(object):
# length is computed correctly # length is computed correctly
assert p.header.length + len(p.header) == len(p) assert p.header.length + len(p.header) == len(p)
assert len(p) == len(b) - len(_trailer) if packet not in ('tests/testdata/packets/11.partial.literal',):
assert len(p.__bytes__()) == len(b) - len(_trailer) assert len(p) == len(b) - len(_trailer)
assert len(p.__bytes__()) == len(b) - len(_trailer)
# __bytes__ output is correct # __bytes__ output is correct
assert p.__bytes__() == b[:-len(_trailer)] assert p.__bytes__() == b[:-len(_trailer)]
# instantiated class is what we expected # instantiated class is what we expected
if hasattr(p.header, 'version') and (p.header.tag, p.header.version) in _pclasses: if hasattr(p.header, 'version') and (p.header.tag, p.header.version) in _pclasses: