[tor-commits] [stem/master] Unpack only a single cell
atagar at torproject.org
atagar at torproject.org
Sun Jan 21 02:04:04 UTC 2018
commit e548a715bc50c4c1b8a773d49b1c6d00442a1ea7
Author: Damian Johnson <atagar at torproject.org>
Date: Tue Jan 16 09:46:44 2018 -0800
Unpack only a single cell
When first establishing a link the first cell we receive (VERSIONS) determines
the link protocol version used to unpack all future cells. As such we
definitely want an 'unpack just one cell' function like endosome.
---
stem/client/cell.py | 33 ++++++++++++++-------------------
test/unit/client/cell.py | 16 ++++++++++------
2 files changed, 24 insertions(+), 25 deletions(-)
diff --git a/stem/client/cell.py b/stem/client/cell.py
index 98ab198c..8a6480c7 100644
--- a/stem/client/cell.py
+++ b/stem/client/cell.py
@@ -95,39 +95,34 @@ class Cell(object):
@staticmethod
def unpack(content, link_version):
"""
- Unpacks encoded bytes into a series of cells.
+ Unpacks the first cell.
:param bytes content: payload to decode
:param int link_version: link protocol version
- :returns: **list** of :class:`~stem.client.cell.Cell` subclasses
+ :returns: (:class:`~stem.client.cell.Cell`, remainder) tuple
:raises:
* ValueError if content is malformed
* NotImplementedError if unable to unpack this cell type
"""
- cells = []
+ circ_id, content = Size.SHORT.pop(content) if link_version < 4 else Size.LONG.pop(content)
+ command, content = Size.CHAR.pop(content)
+ cls = Cell.by_value(command)
- while content:
- circ_id, content = Size.SHORT.pop(content) if link_version < 4 else Size.LONG.pop(content)
- command, content = Size.CHAR.pop(content)
- cls = Cell.by_value(command)
-
- if cls.IS_FIXED_SIZE:
- payload_len = FIXED_PAYLOAD_LEN
- else:
- payload_len, content = Size.SHORT.pop(content)
-
- if len(content) < payload_len:
- raise ValueError('%s cell should have a payload of %i bytes, but only had %i' % (cls.NAME, payload_len, len(content)))
+ if cls.IS_FIXED_SIZE:
+ payload_len = FIXED_PAYLOAD_LEN
+ else:
+ payload_len, content = Size.SHORT.pop(content)
- payload = content[:payload_len]
- content = content[payload_len:]
+ if len(content) < payload_len:
+ raise ValueError('%s cell should have a payload of %i bytes, but only had %i' % (cls.NAME, payload_len, len(content)))
- cells.append(cls._unpack(payload, link_version, circ_id))
+ payload = content[:payload_len]
+ content = content[payload_len:]
- return cells
+ return cls._unpack(payload, link_version, circ_id), content
@classmethod
def _pack(cls, link_version, payload, circ_id = 0):
diff --git a/test/unit/client/cell.py b/test/unit/client/cell.py
index cf7eb684..a0eab2e5 100644
--- a/test/unit/client/cell.py
+++ b/test/unit/client/cell.py
@@ -86,11 +86,12 @@ class TestCell(unittest.TestCase):
(7, '\x1a\xa5\xb3\xbd\x88\xb1C'),
)
- link_cells = Cell.unpack(test_data('new_link_cells'), 2)
- self.assertEqual(4, len(link_cells))
- self.assertEqual(VersionsCell([3, 4, 5]), link_cells[0])
+ content = test_data('new_link_cells')
- certs_cell = link_cells[1]
+ version_cell, content = Cell.unpack(content, 2)
+ self.assertEqual(VersionsCell([3, 4, 5]), version_cell)
+
+ certs_cell, content = Cell.unpack(content, 2)
self.assertEqual(CertsCell, type(certs_cell))
self.assertEqual(len(expected_certs), len(certs_cell.certificates))
@@ -98,14 +99,17 @@ class TestCell(unittest.TestCase):
self.assertEqual(cert_type, certs_cell.certificates[i].type)
self.assertTrue(certs_cell.certificates[i].value.startswith(cert_prefix))
- self.assertEqual(AuthChallengeCell('\x89Y\t\x99\xb2\x1e\xd9*V\xb6\x1bn\n\x05\xd8/\xe3QH\x85\x13Z\x17\xfc\x1c\x00{\xa9\xae\x83^K', [1, 3]), link_cells[2])
+ auth_challenge_cell, content = Cell.unpack(content, 2)
+ self.assertEqual(AuthChallengeCell('\x89Y\t\x99\xb2\x1e\xd9*V\xb6\x1bn\n\x05\xd8/\xe3QH\x85\x13Z\x17\xfc\x1c\x00{\xa9\xae\x83^K', [1, 3]), auth_challenge_cell)
- netinfo_cell = link_cells[3]
+ netinfo_cell, content = Cell.unpack(content, 2)
self.assertEqual(NetinfoCell, type(netinfo_cell))
self.assertEqual(datetime.datetime(2018, 1, 14, 1, 46, 56), netinfo_cell.timestamp)
self.assertEqual(Address(type='IPv4', type_int=4, value='127.0.0.1', value_bin='\x7f\x00\x00\x01'), netinfo_cell.receiver_address)
self.assertEqual([Address(type='IPv4', type_int=4, value='97.113.15.2', value_bin='aq\x0f\x02')], netinfo_cell.sender_addresses)
+ self.assertEqual('', content) # check that we've consumed all of the bytes
+
def test_padding_packing(self):
for cell_bytes, payload in PADDING_CELLS.items():
self.assertEqual(cell_bytes, PaddingCell.pack(2, payload))
More information about the tor-commits
mailing list