Parse partial length headers correctly.
This commit is contained in:
@@ -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:
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
Reference in New Issue
Block a user