Skip to content

Commit 1b2f9f1

Browse files
authored
fix(foundation): warn when PyPCAP, PCAP_CT or PyPCAPFile ignores Extractor(context=) (#2313) (#2332)
Problem: the DPKT, Scapy and PyShark engines warn that a parsing context supplied through 'context=' is ignored, but the PyPCAP, PCAP_CT and PyPCAPFile engines never read Extractor._exctx and drop it silently. Fix: each of the three engines' run() emits the same AttributeWarning, naming the engine, right after its layer/protocol threshold warning, and lists it under Warns: as DPKT and Scapy do. Test: each engine's unit test drives run() with a non-empty _exctx and pins the exact warning; the shared fixtures gain an empty _exctx, so the threshold tests' call counts also pin that no context stays silent.
1 parent 15c2e57 commit 1b2f9f1

6 files changed

Lines changed: 86 additions & 0 deletions

File tree

‎pcapkit/foundation/engines/pcap_ct.py‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,9 @@ def run(self) -> 'None':
309309
and/or :attr:`self.extractor._exptl <pcapkit.foundation.extraction.Extractor._exptl>`
310310
is provided as the pcap-ct engine does not
311311
support such operations.
312+
* if :attr:`self.extractor._exctx <pcapkit.foundation.extraction.Extractor._exctx>`
313+
is provided, as the pcap-ct engine does not parse with :mod:`pcapkit`'s
314+
own protocol implementations.
312315
* if reassembly and/or flow tracing is enabled, as the pcap-ct
313316
engine performs no protocol dissection and so cannot support
314317
either operation.
@@ -357,6 +360,12 @@ def run(self) -> 'None':
357360
f"'layer={ext._exlyr}' and 'protocol={ext._exptl}' ignored",
358361
AttributeWarning, stacklevel=stacklevel())
359362

363+
if ext._exctx:
364+
warn("'Extractor(engine=pcap_ct)' does not parse with pcapkit's own protocol "
365+
"implementations, so the parsing context supplied through "
366+
"'context=' is ignored",
367+
AttributeWarning, stacklevel=stacklevel())
368+
360369
if ext.magic_number not in PCAP.MAGIC_NUMBER:
361370
raise FormatError(f'unsupported file format: {ext.magic_number!r}; '
362371
'the pcap-ct engine reads PCAP savefiles only')

‎pcapkit/foundation/engines/pypcap.py‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,9 @@ def run(self) -> 'None':
262262
and/or :attr:`self.extractor._exptl <pcapkit.foundation.extraction.Extractor._exptl>`
263263
is provided as the PyPCAP engine does not
264264
support such operations.
265+
* if :attr:`self.extractor._exctx <pcapkit.foundation.extraction.Extractor._exctx>`
266+
is provided, as the PyPCAP engine does not parse with :mod:`pcapkit`'s
267+
own protocol implementations.
265268
* if reassembly and/or flow tracing is enabled, as the PyPCAP
266269
engine performs no protocol dissection and so cannot support
267270
either operation.
@@ -284,6 +287,12 @@ def run(self) -> 'None':
284287
f"'layer={ext._exlyr}' and 'protocol={ext._exptl}' ignored",
285288
AttributeWarning, stacklevel=stacklevel())
286289

290+
if ext._exctx:
291+
warn("'Extractor(engine=pypcap)' does not parse with pcapkit's own protocol "
292+
"implementations, so the parsing context supplied through "
293+
"'context=' is ignored",
294+
AttributeWarning, stacklevel=stacklevel())
295+
287296
if ext.magic_number not in PCAP.MAGIC_NUMBER:
288297
raise FormatError(f'unsupported file format: {ext.magic_number!r}; '
289298
'the PyPCAP engine reads PCAP savefiles only')

‎pcapkit/foundation/engines/pypcapfile.py‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,9 @@ def run(self) -> 'None':
221221
and/or :attr:`self.extractor._exptl <pcapkit.foundation.extraction.Extractor._exptl>`
222222
is provided as the PyPCAPFile engine does not
223223
support such operations.
224+
* if :attr:`self.extractor._exctx <pcapkit.foundation.extraction.Extractor._exctx>`
225+
is provided, as the PyPCAPFile engine does not parse with :mod:`pcapkit`'s
226+
own protocol implementations.
224227
* if IPv6 reassembly is enabled, as |pcapfile|_ has no IPv6
225228
decoder.
226229
* if |pcapfile|_ has no decoder for the savefile's link layer
@@ -241,6 +244,12 @@ def run(self) -> 'None':
241244
f"'layer={ext._exlyr}' and 'protocol={ext._exptl}' ignored",
242245
AttributeWarning, stacklevel=stacklevel())
243246

247+
if ext._exctx:
248+
warn("'Extractor(engine=pypcapfile)' does not parse with pcapkit's own protocol "
249+
"implementations, so the parsing context supplied through "
250+
"'context=' is ignored",
251+
AttributeWarning, stacklevel=stacklevel())
252+
244253
if ext.magic_number not in PCAP.MAGIC_NUMBER:
245254
raise FormatError(f'unsupported file format: {ext.magic_number!r}; '
246255
'the PyPCAPFile engine reads PCAP savefiles only')

‎tests/foundation/engines/test_pcap_ct_engine.py‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ def make_extractor(self, **overrides):
169169
'_frnum': 0,
170170
'_exlyr': 'none',
171171
'_exptl': 'null',
172+
'_exctx': {},
172173
'_vfunc': mock.Mock(),
173174
'magic_number': PCAP_MAGIC,
174175
}
@@ -389,6 +390,25 @@ def test_run_warns_on_layer_and_protocol_threshold(self) -> None:
389390
self.assertIn('protocol and layer threshold', warn.call_args.args[0])
390391
self.assertIs(warn.call_args.args[1], AttributeWarning)
391392

393+
def test_run_warns_that_a_parsing_context_is_ignored(self) -> None:
394+
from pcapkit.utilities.warnings import AttributeWarning
395+
396+
# #2313: the engine never parses with pcapkit's own protocols, so a
397+
# ``context=`` has no effect and the caller is told so, as DPKT, Scapy and
398+
# PyShark already do. The fixture's empty ``_exctx`` stays silent, which
399+
# the threshold test above pins through its call count.
400+
extractor, _ = self.make_extractor(_exctx={'ipv4': mock.sentinel.context})
401+
engine = self.engine(extractor)
402+
with mock.patch.object(engine._expkg, 'pcap', return_value=FakeHandle()):
403+
with mock.patch('pcapkit.foundation.engines.pcap_ct.warn') as warn:
404+
engine.run()
405+
self.assertEqual(warn.call_count, 1)
406+
self.assertEqual(warn.call_args.args[0],
407+
"'Extractor(engine=pcap_ct)' does not parse with pcapkit's own "
408+
"protocol implementations, so the parsing context supplied "
409+
"through 'context=' is ignored")
410+
self.assertIs(warn.call_args.args[1], AttributeWarning)
411+
392412
def test_run_rejects_pcapng_rather_than_reading_it_approximately(self) -> None:
393413
from pcapkit.utilities.exceptions import FormatError
394414

‎tests/foundation/engines/test_pypcap_engine.py‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ def make_extractor(self, **overrides):
112112
'_frnum': 0,
113113
'_exlyr': 'none',
114114
'_exptl': 'null',
115+
'_exctx': {},
115116
'_vfunc': mock.Mock(),
116117
'magic_number': PCAP_MAGIC,
117118
}
@@ -308,6 +309,25 @@ def test_run_warns_on_layer_and_protocol_threshold(self) -> None:
308309
self.assertIn('protocol and layer threshold', warn.call_args.args[0])
309310
self.assertIs(warn.call_args.args[1], AttributeWarning)
310311

312+
def test_run_warns_that_a_parsing_context_is_ignored(self) -> None:
313+
from pcapkit.utilities.warnings import AttributeWarning
314+
315+
# #2313: the engine never parses with pcapkit's own protocols, so a
316+
# ``context=`` has no effect and the caller is told so, as DPKT, Scapy and
317+
# PyShark already do. The fixture's empty ``_exctx`` stays silent, which
318+
# the threshold test above pins through its call count.
319+
extractor, _ = self.make_extractor(_exctx={'ipv4': mock.sentinel.context})
320+
engine = self.engine(extractor)
321+
with mock.patch.object(engine._expkg, 'pcap', return_value=FakeHandle()):
322+
with mock.patch('pcapkit.foundation.engines.pypcap.warn') as warn:
323+
engine.run()
324+
self.assertEqual(warn.call_count, 1)
325+
self.assertEqual(warn.call_args.args[0],
326+
"'Extractor(engine=pypcap)' does not parse with pcapkit's own "
327+
"protocol implementations, so the parsing context supplied "
328+
"through 'context=' is ignored")
329+
self.assertIs(warn.call_args.args[1], AttributeWarning)
330+
311331
def test_run_rejects_pcapng_rather_than_yielding_no_frames(self) -> None:
312332
from pcapkit.utilities.exceptions import FormatError
313333

‎tests/foundation/engines/test_pypcapfile_engine.py‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@ def make_extractor(self, **overrides):
196196
'_frnum': 0,
197197
'_exlyr': 'none',
198198
'_exptl': 'null',
199+
'_exctx': {},
199200
'_vfunc': mock.Mock(),
200201
'magic_number': PCAP_MAGIC,
201202
}
@@ -257,6 +258,24 @@ def test_run_warns_on_layer_and_protocol_threshold(self) -> None:
257258
self.assertIn('protocol and layer threshold', warn.call_args.args[0])
258259
self.assertIs(warn.call_args.args[1], AttributeWarning)
259260

261+
def test_run_warns_that_a_parsing_context_is_ignored(self) -> None:
262+
from pcapkit.utilities.warnings import AttributeWarning
263+
264+
# #2313: the engine never parses with pcapkit's own protocols, so a
265+
# ``context=`` has no effect and the caller is told so, as DPKT, Scapy and
266+
# PyShark already do. The fixture's empty ``_exctx`` stays silent, which
267+
# the threshold test above pins through its call count.
268+
extractor, _ = self.make_extractor(_exctx={'ipv4': mock.sentinel.context})
269+
engine = self.engine(extractor)
270+
with mock.patch('pcapkit.foundation.engines.pypcapfile.warn') as warn:
271+
engine.run()
272+
self.assertEqual(warn.call_count, 1)
273+
self.assertEqual(warn.call_args.args[0],
274+
"'Extractor(engine=pypcapfile)' does not parse with pcapkit's own "
275+
"protocol implementations, so the parsing context supplied "
276+
"through 'context=' is ignored")
277+
self.assertIs(warn.call_args.args[1], AttributeWarning)
278+
260279
def test_run_rejects_pcapng(self) -> None:
261280
from pcapkit.utilities.exceptions import FormatError
262281

0 commit comments

Comments
 (0)