diff --git a/pcapkit/foundation/engines/pcap_ct.py b/pcapkit/foundation/engines/pcap_ct.py index e221a41911..511d3184bd 100644 --- a/pcapkit/foundation/engines/pcap_ct.py +++ b/pcapkit/foundation/engines/pcap_ct.py @@ -309,6 +309,9 @@ def run(self) -> 'None': and/or :attr:`self.extractor._exptl ` is provided as the pcap-ct engine does not support such operations. + * if :attr:`self.extractor._exctx ` + is provided, as the pcap-ct engine does not parse with :mod:`pcapkit`'s + own protocol implementations. * if reassembly and/or flow tracing is enabled, as the pcap-ct engine performs no protocol dissection and so cannot support either operation. @@ -357,6 +360,12 @@ def run(self) -> 'None': f"'layer={ext._exlyr}' and 'protocol={ext._exptl}' ignored", AttributeWarning, stacklevel=stacklevel()) + if ext._exctx: + warn("'Extractor(engine=pcap_ct)' does not parse with pcapkit's own protocol " + "implementations, so the parsing context supplied through " + "'context=' is ignored", + AttributeWarning, stacklevel=stacklevel()) + if ext.magic_number not in PCAP.MAGIC_NUMBER: raise FormatError(f'unsupported file format: {ext.magic_number!r}; ' 'the pcap-ct engine reads PCAP savefiles only') diff --git a/pcapkit/foundation/engines/pypcap.py b/pcapkit/foundation/engines/pypcap.py index 4f2d79c3b7..21c2eb0455 100644 --- a/pcapkit/foundation/engines/pypcap.py +++ b/pcapkit/foundation/engines/pypcap.py @@ -262,6 +262,9 @@ def run(self) -> 'None': and/or :attr:`self.extractor._exptl ` is provided as the PyPCAP engine does not support such operations. + * if :attr:`self.extractor._exctx ` + is provided, as the PyPCAP engine does not parse with :mod:`pcapkit`'s + own protocol implementations. * if reassembly and/or flow tracing is enabled, as the PyPCAP engine performs no protocol dissection and so cannot support either operation. @@ -284,6 +287,12 @@ def run(self) -> 'None': f"'layer={ext._exlyr}' and 'protocol={ext._exptl}' ignored", AttributeWarning, stacklevel=stacklevel()) + if ext._exctx: + warn("'Extractor(engine=pypcap)' does not parse with pcapkit's own protocol " + "implementations, so the parsing context supplied through " + "'context=' is ignored", + AttributeWarning, stacklevel=stacklevel()) + if ext.magic_number not in PCAP.MAGIC_NUMBER: raise FormatError(f'unsupported file format: {ext.magic_number!r}; ' 'the PyPCAP engine reads PCAP savefiles only') diff --git a/pcapkit/foundation/engines/pypcapfile.py b/pcapkit/foundation/engines/pypcapfile.py index 370de917b1..092bba9997 100644 --- a/pcapkit/foundation/engines/pypcapfile.py +++ b/pcapkit/foundation/engines/pypcapfile.py @@ -221,6 +221,9 @@ def run(self) -> 'None': and/or :attr:`self.extractor._exptl ` is provided as the PyPCAPFile engine does not support such operations. + * if :attr:`self.extractor._exctx ` + is provided, as the PyPCAPFile engine does not parse with :mod:`pcapkit`'s + own protocol implementations. * if IPv6 reassembly is enabled, as |pcapfile|_ has no IPv6 decoder. * if |pcapfile|_ has no decoder for the savefile's link layer @@ -241,6 +244,12 @@ def run(self) -> 'None': f"'layer={ext._exlyr}' and 'protocol={ext._exptl}' ignored", AttributeWarning, stacklevel=stacklevel()) + if ext._exctx: + warn("'Extractor(engine=pypcapfile)' does not parse with pcapkit's own protocol " + "implementations, so the parsing context supplied through " + "'context=' is ignored", + AttributeWarning, stacklevel=stacklevel()) + if ext.magic_number not in PCAP.MAGIC_NUMBER: raise FormatError(f'unsupported file format: {ext.magic_number!r}; ' 'the PyPCAPFile engine reads PCAP savefiles only') diff --git a/tests/foundation/engines/test_pcap_ct_engine.py b/tests/foundation/engines/test_pcap_ct_engine.py index 0572306a91..f7337d238a 100644 --- a/tests/foundation/engines/test_pcap_ct_engine.py +++ b/tests/foundation/engines/test_pcap_ct_engine.py @@ -169,6 +169,7 @@ def make_extractor(self, **overrides): '_frnum': 0, '_exlyr': 'none', '_exptl': 'null', + '_exctx': {}, '_vfunc': mock.Mock(), 'magic_number': PCAP_MAGIC, } @@ -389,6 +390,25 @@ def test_run_warns_on_layer_and_protocol_threshold(self) -> None: self.assertIn('protocol and layer threshold', warn.call_args.args[0]) self.assertIs(warn.call_args.args[1], AttributeWarning) + def test_run_warns_that_a_parsing_context_is_ignored(self) -> None: + from pcapkit.utilities.warnings import AttributeWarning + + # #2313: the engine never parses with pcapkit's own protocols, so a + # ``context=`` has no effect and the caller is told so, as DPKT, Scapy and + # PyShark already do. The fixture's empty ``_exctx`` stays silent, which + # the threshold test above pins through its call count. + extractor, _ = self.make_extractor(_exctx={'ipv4': mock.sentinel.context}) + engine = self.engine(extractor) + with mock.patch.object(engine._expkg, 'pcap', return_value=FakeHandle()): + with mock.patch('pcapkit.foundation.engines.pcap_ct.warn') as warn: + engine.run() + self.assertEqual(warn.call_count, 1) + self.assertEqual(warn.call_args.args[0], + "'Extractor(engine=pcap_ct)' does not parse with pcapkit's own " + "protocol implementations, so the parsing context supplied " + "through 'context=' is ignored") + self.assertIs(warn.call_args.args[1], AttributeWarning) + def test_run_rejects_pcapng_rather_than_reading_it_approximately(self) -> None: from pcapkit.utilities.exceptions import FormatError diff --git a/tests/foundation/engines/test_pypcap_engine.py b/tests/foundation/engines/test_pypcap_engine.py index f1fbb9b146..89a56ddbb9 100644 --- a/tests/foundation/engines/test_pypcap_engine.py +++ b/tests/foundation/engines/test_pypcap_engine.py @@ -112,6 +112,7 @@ def make_extractor(self, **overrides): '_frnum': 0, '_exlyr': 'none', '_exptl': 'null', + '_exctx': {}, '_vfunc': mock.Mock(), 'magic_number': PCAP_MAGIC, } @@ -308,6 +309,25 @@ def test_run_warns_on_layer_and_protocol_threshold(self) -> None: self.assertIn('protocol and layer threshold', warn.call_args.args[0]) self.assertIs(warn.call_args.args[1], AttributeWarning) + def test_run_warns_that_a_parsing_context_is_ignored(self) -> None: + from pcapkit.utilities.warnings import AttributeWarning + + # #2313: the engine never parses with pcapkit's own protocols, so a + # ``context=`` has no effect and the caller is told so, as DPKT, Scapy and + # PyShark already do. The fixture's empty ``_exctx`` stays silent, which + # the threshold test above pins through its call count. + extractor, _ = self.make_extractor(_exctx={'ipv4': mock.sentinel.context}) + engine = self.engine(extractor) + with mock.patch.object(engine._expkg, 'pcap', return_value=FakeHandle()): + with mock.patch('pcapkit.foundation.engines.pypcap.warn') as warn: + engine.run() + self.assertEqual(warn.call_count, 1) + self.assertEqual(warn.call_args.args[0], + "'Extractor(engine=pypcap)' does not parse with pcapkit's own " + "protocol implementations, so the parsing context supplied " + "through 'context=' is ignored") + self.assertIs(warn.call_args.args[1], AttributeWarning) + def test_run_rejects_pcapng_rather_than_yielding_no_frames(self) -> None: from pcapkit.utilities.exceptions import FormatError diff --git a/tests/foundation/engines/test_pypcapfile_engine.py b/tests/foundation/engines/test_pypcapfile_engine.py index 941e131911..a5b69865c4 100644 --- a/tests/foundation/engines/test_pypcapfile_engine.py +++ b/tests/foundation/engines/test_pypcapfile_engine.py @@ -196,6 +196,7 @@ def make_extractor(self, **overrides): '_frnum': 0, '_exlyr': 'none', '_exptl': 'null', + '_exctx': {}, '_vfunc': mock.Mock(), 'magic_number': PCAP_MAGIC, } @@ -257,6 +258,24 @@ def test_run_warns_on_layer_and_protocol_threshold(self) -> None: self.assertIn('protocol and layer threshold', warn.call_args.args[0]) self.assertIs(warn.call_args.args[1], AttributeWarning) + def test_run_warns_that_a_parsing_context_is_ignored(self) -> None: + from pcapkit.utilities.warnings import AttributeWarning + + # #2313: the engine never parses with pcapkit's own protocols, so a + # ``context=`` has no effect and the caller is told so, as DPKT, Scapy and + # PyShark already do. The fixture's empty ``_exctx`` stays silent, which + # the threshold test above pins through its call count. + extractor, _ = self.make_extractor(_exctx={'ipv4': mock.sentinel.context}) + engine = self.engine(extractor) + with mock.patch('pcapkit.foundation.engines.pypcapfile.warn') as warn: + engine.run() + self.assertEqual(warn.call_count, 1) + self.assertEqual(warn.call_args.args[0], + "'Extractor(engine=pypcapfile)' does not parse with pcapkit's own " + "protocol implementations, so the parsing context supplied " + "through 'context=' is ignored") + self.assertIs(warn.call_args.args[1], AttributeWarning) + def test_run_rejects_pcapng(self) -> None: from pcapkit.utilities.exceptions import FormatError