commit 40ca0ca23f2f3fc3cab5ece39370ddb565029501 Author: Dave Rolek dmr-x@riseup.net Date: Sun Aug 19 04:32:52 2018 +0000
Add interpret_cell instance method to BaseRelayCell
This method facilitates separating decryption / recognition of a cell from the interpretation of a cell. Many places in the spec indicate that cells should be dropped (ignored) under certain conditions, but that such cells should still be accounted for within the running decryption / digest.
Furthermore, it may be useful in some cases to convert between raw cells and interpreted cells, without including the other steps of encryption / decryption.
This additionally allows removing one of the interim TODOs in the RELAY cell unit tests. Arguably the tests need some rework with all these changes, but that can come a bit later.
Not yet used, beyond the aforementioned unit tests.
This method will probably evolve a decent amount, since the unit is still in a state of high flux. --- stem/client/cell.py | 35 +++++++++++++++++++++++++++++++++++ test/unit/client/cell.py | 4 ++-- 2 files changed, 37 insertions(+), 2 deletions(-)
diff --git a/stem/client/cell.py b/stem/client/cell.py index 250d400a..a96b2f7b 100644 --- a/stem/client/cell.py +++ b/stem/client/cell.py @@ -408,6 +408,41 @@ class BaseRelayCell(CircuitCell):
return digest_matches, digest_to_return
+ def interpret_cell(self): + """ + Interprets the cell payload, returning a new + :class:`~stem.client.cell.RelayCell` class or subclass according to its + contents. + + This method should only be used on fully decrypted cells, but that + responsibility is relegated to the caller. + + Furthermore, this interpretation may cause an exception for a NYI relay + command, a malformed cell, or some other reason. + + :returns: :class:`~stem.client.cell.RelayCell` class or subclass + """ + + # TODO: this mapping is quite hardcoded right now, but probably needs to be + # completely reworked once the Cell class hierarchy is better fleshed out. + # + # (It doesn't really make sense to have anything beyond this hack in the + # interim.) + # + # At that time, it would probably be modeled after Cell.by_value(), albeit + # specialized for the multiple types of RELAY / RELAY_EARLY cells. + + relay_cells_by_value = { + RawRelayCell.VALUE: RelayCell, + RelayEarlyCell.VALUE: RelayEarlyCell, + } + new_cls = relay_cells_by_value[self.VALUE] + + dummy_link_protocol = None + new_cell = new_cls._unpack(self.payload, self.circ_id, dummy_link_protocol) + + return new_cell + def __hash__(self): return stem.util._hash_attr(self, 'circ_id', 'payload', cache = True)
diff --git a/test/unit/client/cell.py b/test/unit/client/cell.py index 3e091ee5..b4c0bd94 100644 --- a/test/unit/client/cell.py +++ b/test/unit/client/cell.py @@ -235,12 +235,12 @@ class TestCell(unittest.TestCase): self.assertEqual(cell_bytes, RelayCell(circ_id, command, data, digest, stream_id, unused = unused).pack(link_protocol)) self.assertEqual(cell_bytes, RelayCell(circ_id, command_int, data, digest, stream_id, unused = unused).pack(link_protocol))
- # TODO - temporarily, we hack the interim tests by unpacking info via RawRelayCell + # first unpack via RawRelayCell, then interpret into RelayCell raw_cell = Cell.pop(cell_bytes, link_protocol)[0] self.assertEqual(circ_id, raw_cell.circ_id) self.assertEqual(cell_bytes[-FIXED_PAYLOAD_LEN:], raw_cell.payload)
- cell = RelayCell._unpack(raw_cell.payload, raw_cell.circ_id, link_protocol) + cell = raw_cell.interpret_cell() self.assertEqual(circ_id, cell.circ_id) self.assertEqual(command, cell.command) self.assertEqual(command_int, cell.command_int)