Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,40 @@ def maybe_skip_member(app: 'Sphinx', what: str, name: str, # pylint: disable=un
return skip


def skip_enum_value_hook(app: 'Sphinx', what: str, name: str, # pylint: disable=unused-argument
obj: 'Any', skip: bool, options: 'Dict[str, Any]') -> 'Optional[bool]': # pylint: disable=unused-argument
"""Skip the enum machinery's own ``_generate_next_value_`` hook.

The enum metaclass copies ``_generate_next_value_`` into the namespace of
every enumeration it creates, so ``:members:`` finds it as the documented
class's own member. ``exclude-members`` cannot remove it: autodoc applies
that first and then lets ``autodoc-skip-member`` overrule it, and
napoleon's handler, with ``napoleon_include_private_with_doc`` on, includes
a private member that has a docstring and was defined in a class body --
true of the standard library's hooks and of ``aenum``'s ``StrEnum`` one.
None of them is part of any pcapkit enumeration's interface.

Args:
app: Sphinx application.
what: Type of the object whose member is being considered.
name: Name of the member.
obj: The member itself.
skip: Whether autodoc would skip it.
options: Directive options.

Returns:
:obj:`True` for a ``_generate_next_value_`` that pcapkit does not
define itself, and :obj:`None` for anything else, which leaves the
decision to the other handlers.

"""
if name == '_generate_next_value_':
module = getattr(obj, '__module__', None) or ''
if module.partition('.')[0] != 'pcapkit':
return True
return None


def bind_type_checking_names(app: 'Sphinx') -> None:
"""Execute every ``pcapkit`` module's ``if TYPE_CHECKING:`` block.

Expand Down Expand Up @@ -555,6 +589,10 @@ def restore_enum_member_docstring(app: 'Sphinx', what: str, name: str, # pylint
def setup(app: 'Sphinx') -> None:
app.connect('builder-inited', bind_type_checking_names)
app.connect('autodoc-skip-member', maybe_skip_member)
# NB: before napoleon's ``autodoc-skip-member`` handler, which connects at the
# default 500 and returns ``False`` for this hook; the first answer that is
# not ``None`` is the one autodoc uses.
app.connect('autodoc-skip-member', skip_enum_value_hook, priority=400)
# NB: below ``sphinx_autodoc_typehints``, which connects at the default 500 and
# would otherwise win the tie on registration order -- conf.py's ``setup`` runs
# after the extensions in ``extensions`` have been set up.
Expand Down
7 changes: 3 additions & 4 deletions docs/source/pcapkit/protocols/application/application.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@ Base Protocol

:mod:`pcapkit.protocols.application.application` contains only
:class:`~pcapkit.protocols.application.application.Application`,
which is a base class for application layer protocols, eg.
:class:`HTTP/1.* <pcapkit.protocols.application.httpv1.HTTP>`,
:class:`HTTP/2 <pcapkit.protocols.application.httpv2.HTTP>`
and etc.
which is a base class for application layer protocols, e.g.
:class:`HTTP/1.* <pcapkit.protocols.application.httpv1.HTTP>` and
:class:`HTTP/2 <pcapkit.protocols.application.httpv2.HTTP>`.

.. versionchanged:: 1.5.0

Expand Down
2 changes: 1 addition & 1 deletion docs/source/pcapkit/protocols/application/http.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ HTTP - Hypertext Transfer Protocol
:mod:`pcapkit.protocols.application.http` contains
:class:`~pcapkit.protocols.application.http.HTTP`,
which is a base class for Hypertext Transfer
Protocol (HTTP) [*]_ family, eg.
Protocol (HTTP) [*]_ family, e.g.
:class:`HTTP/1.* <pcapkit.protocols.application.httpv1.HTTP>`
and :class:`HTTP/2 <pcapkit.protocols.application.httpv2.HTTP>`,
and :func:`~pcapkit.protocols.application.http.test_start_line`,
Expand Down
59 changes: 29 additions & 30 deletions docs/source/pcapkit/protocols/application/ngap.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ NGAP - NG Application Protocol
:mod:`pcapkit.protocols.application.ngap` contains
:class:`~pcapkit.protocols.application.ngap.NGAP`,
which implements extractor for the NG Application Protocol
(NGAP) [*]_, as specified in 3GPP TS 38.413, and the four enumerations its
(NGAP) [*]_, as specified in 3GPP TS 38.413, and the enumerations its
data models report with:
:class:`~pcapkit.protocols.application.ngap.PDUKind`,
:class:`~pcapkit.protocols.application.ngap.Criticality`,
Expand Down Expand Up @@ -35,10 +35,23 @@ unregistered PPID would, because
:func:`~pcapkit.corekit.decorators.beholder` and falls back to
:class:`~pcapkit.protocols.misc.raw.Raw`.

.. autoclass:: pcapkit.protocols.application.ngap.NGAP
:no-members:
:show-inheritance:

.. autoproperty:: name
.. autoproperty:: length

.. automethod:: read
.. automethod:: make

.. automethod:: __length_hint__
.. automethod:: _make_data

Decoder Dependency
------------------

|pycrate|_ is used rather than a PER codec of our own, for two reasons. It
|pycrate|_ is used rather than a PER codec of our own. It
**ships NGAP already compiled**, at ``pycrate_asn1dir/NGAP.py``, so the 3GPP
ASN.1 source does not have to be vendored here and tracked across releases; and
it is **pure Python**, with no compiled extension to build on any platform.
Expand All @@ -52,19 +65,18 @@ Generic Conversion
The decoded value tree is mapped into :class:`~pcapkit.corekit.infoclass.Info`
objects **structurally**, by ASN.1 shape rather than by procedure:

=============================== ==========================================================
ASN.1 / |pycrate|_ shape :mod:`pcapkit` model
=============================== ==========================================================
``SEQUENCE`` / ``SET`` (a dict) :class:`~pcapkit.protocols.data.application.ngap.Sequence`
``SEQUENCE OF`` (a list) :obj:`list`
``CHOICE`` / open type :class:`~pcapkit.protocols.data.application.ngap.Choice`
``BIT STRING`` :class:`~pcapkit.protocols.data.application.ngap.BitString`
``INTEGER``, ``OCTET STRING``, kept as :obj:`int`, :obj:`bytes`, :obj:`str`
``ENUMERATED``, ``BOOLEAN``
=============================== ==========================================================

That is a deliberate trade. Every one of the 81 elementary procedures and 438
protocol IEs works on the day it is decoded, and a new 3GPP release needs no
========================================================== ==========================================================
ASN.1 / |pycrate|_ shape :mod:`pcapkit` model
========================================================== ==========================================================
``SEQUENCE`` / ``SET`` (a dict) :class:`~pcapkit.protocols.data.application.ngap.Sequence`
``SEQUENCE OF`` (a list) :obj:`list`
``CHOICE`` / open type :class:`~pcapkit.protocols.data.application.ngap.Choice`
``BIT STRING`` :class:`~pcapkit.protocols.data.application.ngap.BitString`
``INTEGER``, ``OCTET STRING``, ``ENUMERATED``, ``BOOLEAN`` kept as :obj:`int`, :obj:`bytes`, :obj:`str`, :obj:`bool`
========================================================== ==========================================================

That is a deliberate trade. Every elementary procedure and protocol IE
works on the day it is decoded, and a new 3GPP release needs no
code change here; what is given up is per-IE typing, so an IE's value is
reported in the specification's own shape rather than as a
:mod:`pcapkit`-specific model. The fields worth reading at a glance -- the PDU
Expand All @@ -82,8 +94,8 @@ Known Limitations
degrades to :class:`~pcapkit.protocols.misc.raw.Raw`.
* **The specification version is that of the installed decoder, not this
package's.** The IE and procedure enumerations were generated from
``NGAP_Constants`` of |pycrate|_ 0.8.1 (Release-18-era: 81 procedure codes,
438 protocol IE IDs, highest 443). A |pycrate|_ that carries a newer NGAP will decode IEs that
``NGAP_Constants`` of |pycrate|_ 0.8.1 (Release-18-era). A |pycrate|_ that
carries a newer NGAP will decode IEs that
:class:`~pcapkit.const.ngap.procedure_code.ProcedureCode` and
:class:`~pcapkit.const.ngap.protocol_ie.ProtocolIE` do not name. Such a
value resolves to a non-registering member called ``Unassigned`` rather than
Expand All @@ -95,19 +107,6 @@ Known Limitations
vendor defined, so the generic conversion reports whatever ASN.1 shape the
encoding declares and cannot name the fields.

.. autoclass:: pcapkit.protocols.application.ngap.NGAP
:no-members:
:show-inheritance:

.. autoproperty:: name
.. autoproperty:: length

.. automethod:: read
.. automethod:: make

.. automethod:: __length_hint__
.. automethod:: _make_data

Auxiliary Functions
-------------------

Expand Down
7 changes: 6 additions & 1 deletion docs/source/pcapkit/protocols/application/ospf.rst
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,12 @@ as below:
.. versionremoved:: 1.5.0

``pcapkit.protocols.link.ospf``, ``pcapkit.protocols.data.link.ospf`` and
``pcapkit.protocols.schema.link.ospf``, with no alias (:issue:`719`).
``pcapkit.protocols.schema.link.ospf``, the ``OSPF`` name that
``pcapkit.protocols.link``, ``pcapkit.protocols.data.link`` and
``pcapkit.protocols.schema.link`` each exported, and the
``OSPF_CrytographicAuthentication`` name that
``pcapkit.protocols.data.link`` and ``pcapkit.protocols.schema.link``
exported, with no alias (:issue:`719`, :issue:`1090`).

.. versionchanged:: 1.5.0

Expand Down
3 changes: 2 additions & 1 deletion docs/source/pcapkit/protocols/application/rarp.rst
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ Octets Bits Name Description

.. versionremoved:: 1.5.0

``pcapkit.protocols.link.rarp``, with no alias (:issue:`719`).
``pcapkit.protocols.link.rarp``, and the ``RARP`` and ``DRARP`` names
that ``pcapkit.protocols.link`` exported, with no alias (:issue:`719`).

.. autoclass:: pcapkit.protocols.application.rarp.RARP
:no-members:
Expand Down
2 changes: 1 addition & 1 deletion docs/source/pcapkit/protocols/misc/pcap.rst
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ whose structure is described as below:

.. versionchanged:: 1.5.0

``bytes(frame)`` and :attr:`~pcapkit.protocols.misc.pcap.frame.Frame.packet`
``bytes(frame)`` and :attr:`~pcapkit.protocols.protocol.Protocol.packet`
hold this frame's own octets, where they held the next frame's
(:issue:`357`), and the parsed ``time`` is timezone-aware UTC. The parsed
``len`` is the on-wire length and ``cap_len`` the captured one, where the
Expand Down
7 changes: 4 additions & 3 deletions docs/source/pcapkit/protocols/misc/pcapng.rst
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ which implements extractor for PCAP-NG file format [*]_, and the
.. autoproperty:: ts_timezone
.. autoproperty:: linktype
.. autoproperty:: block
.. autoproperty:: packet

.. automethod:: register
.. automethod:: register_block
Expand Down Expand Up @@ -225,9 +226,9 @@ IANA registry.

.. versionremoved:: 1.5.0

``pcapkit.protocols.misc.pcapng.TLSKeyLabel``, now
:class:`pcapkit.const.pcapng.tls_key_label.TLSKeyLabel` (:issue:`886`,
:issue:`1744`).
``pcapkit.protocols.misc.pcapng.TLSKeyLabel``, with no alias; use
:class:`pcapkit.const.pcapng.tls_key_label.TLSKeyLabel` instead
(:issue:`886`, :issue:`1744`).

.. autoclass:: pcapkit.protocols.misc.pcapng.WireGuardKeyLabel
:members:
Expand Down
8 changes: 7 additions & 1 deletion docs/source/pcapkit/protocols/protocol.rst
Original file line number Diff line number Diff line change
Expand Up @@ -130,11 +130,15 @@ starts at the first layer it dissects. One chain of extension headers is also bo
its own, by :data:`~pcapkit.utilities.config.EXTENSION_HEADER_LIMIT`.
The ``pyshark``, ``scapy`` and ``pypcapfile`` engines dissect with their own
parsers, which do not apply the frame's layer bound (:issue:`1609`). The
``dpkt`` toolkit reads what :mod:`dpkt` decodes, which applies neither bound.
``dpkt`` toolkit reads what ``dpkt`` decodes, which applies neither bound.

Data Models
-----------

.. autoclass:: pcapkit.protocols.data.protocol.Protocol
:members:
:show-inheritance:

.. autoclass:: pcapkit.protocols.data.protocol.Packet
:members:
:show-inheritance:
Expand Down Expand Up @@ -189,6 +193,7 @@ Internal Definitions
_make_data
_make_index
_make_payload
_packing_target
_lookup_registry
_lookup_next_layer
_decode_next_layer
Expand All @@ -214,6 +219,7 @@ Internal Definitions
:meth:`~Protocol.expand_comp`, :meth:`~Protocol._read_packet`,
:meth:`~Protocol._get_payload`, :meth:`~Protocol._make_data`,
:meth:`~Protocol._make_index`, :meth:`~Protocol._make_payload`,
:meth:`~Protocol._packing_target`,
:meth:`~Protocol._lookup_registry`, :meth:`~Protocol._lookup_next_layer`,
:meth:`~Protocol._decode_next_layer`,
:meth:`~Protocol._import_next_layer`,
Expand Down
2 changes: 1 addition & 1 deletion pcapkit/protocols/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

.. module:: pcapkit.protocols

:mod:`pcapkit.protocols` is collection of all protocol families,
:mod:`pcapkit.protocols` is a collection of all protocol families,
with detailed implementation and methods.

"""
Expand Down
2 changes: 1 addition & 1 deletion pcapkit/protocols/application/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
# NNTP, NTP, ONC:RPC, POP, RIP, RTP, SIP, SMTP, SNMP,
# SSH, TELNET, TLS/SSL, XMPP.
#
# NB: NGAP below is the one protocol here whose decoder is an optional
# NB: NGAP's decoder below is an optional
# dependency, c.f. pcapkit.protocols.application.ngap. Importing the module
# is free -- ``pycrate`` is imported inside the parse path, not here.

Expand Down
8 changes: 4 additions & 4 deletions pcapkit/protocols/application/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,13 +144,13 @@ def _decode_next_layer(self, dict_: '_PT', proto: 'Optional[int]' = None, length
proto: next layer protocol index; only the ``-1`` sentinel
(the rest, undissected) is accepted
length: valid (*non-padding*) length
packet: packet info (passed from :meth:`self.unpack <Protocol.unpack>`)
packet: packet info (passed from :meth:`self.unpack <pcapkit.protocols.protocol.Protocol.unpack>`)

Returns:
Current protocol with the undissected remainder as payload.

Raises:
UnsupportedCall: ``proto`` is anything but ``-1``, i.e. a real
UnsupportedCall: If ``proto`` is anything but ``-1``, i.e. a real
protocol dispatch, which this protocol doesn't support.

"""
Expand All @@ -167,14 +167,14 @@ def _import_next_layer(self, proto: 'int', length: 'Optional[int]' = None, *, #
proto: next layer protocol index; only the ``-1`` sentinel
(the rest, undissected) is accepted
length: valid (*non-padding*) length
packet: packet info (passed from :meth:`self.unpack <Protocol.unpack>`)
packet: packet info (passed from :meth:`self.unpack <pcapkit.protocols.protocol.Protocol.unpack>`)

Returns:
Instance of :class:`~pcapkit.protocols.misc.raw.Raw`, or of
:class:`~pcapkit.protocols.misc.null.NoPayload` when nothing remains.

Raises:
UnsupportedCall: ``proto`` is anything but ``-1``, i.e. a real
UnsupportedCall: If ``proto`` is anything but ``-1``, i.e. a real
protocol dispatch, which this protocol doesn't support.

"""
Expand Down
18 changes: 9 additions & 9 deletions pcapkit/protocols/application/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
:mod:`pcapkit.protocols.application.http` contains
:class:`~pcapkit.protocols.application.http.HTTP`,
which is a base class for Hypertext Transfer
Protocol (HTTP) [*]_ family, eg.
Protocol (HTTP) [*]_ family, e.g.
:class:`HTTP/1.* <pcapkit.protocols.application.httpv1.HTTP>`
and :class:`HTTP/2 <pcapkit.protocols.application.httpv2.HTTP>`,
and :func:`~pcapkit.protocols.application.http.test_start_line`,
Expand Down Expand Up @@ -84,7 +84,7 @@ def _test_http2_frame(data: 'bytes') -> 'bool':
sending" (:rfc:`9113#section-4.1`), and each stream rule is one a
receiver "MUST treat as a connection error" when broken (e.g. ``DATA``
on stream 0, :rfc:`9113#section-6.1`), so no frame a conforming peer
sends fails here. Frame types outside the ten that :rfc:`9113` defines
sends fails here. Frame types :rfc:`9113` does not define
are legal and ignored by a receiver (:rfc:`9113#section-5.5`), but on a
payload with no other evidence they are what arbitrary binary looks
like most of the time, so they are not guessed.
Expand Down Expand Up @@ -153,7 +153,7 @@ def test_start_line(data: 'bytes') -> 'bool':
:meth:`HTTP._read_http_header
<pcapkit.protocols.application.httpv1.HTTP._read_http_header>` applies
-- ``_RE_METHOD`` with ``_RE_VERSION`` for a request, ``_RE_VERSION``
with ``_RE_STATUS`` for a response -- which is why those three patterns
with ``_RE_STATUS`` for a response -- which is why those patterns
are defined beside this predicate and
:mod:`~pcapkit.protocols.application.httpv1` imports them from here. The
two must accept the same start lines: a predicate looser than the parser
Expand Down Expand Up @@ -228,7 +228,7 @@ class HTTP(Application[_PT, _ST], Generic[_PT, _ST]):
#: according to that value, so the correct set of names depends on an
#: argument. :obj:`None` therefore opts out of the construction keyword check
#: that :meth:`ProtocolBase.__init__
#: <pcapkit.protocols.protocol.ProtocolBase.__init__>` performs; the two
#: <pcapkit.protocols.protocol.ProtocolBase.__init__>` performs; the
#: versioned classes are checked normally when constructed directly.
__keywords__ = None

Expand Down Expand Up @@ -338,7 +338,7 @@ def make(self,
Args:
version: Version of HTTP.
preface: Whether the HTTP/2 connection preface goes ahead of the
frame; :meth:`pack` writes it.
frame; :meth:`~pcapkit.protocols.protocol.Protocol.pack` writes it.
**kwargs: Arbitrary keyword arguments.

Returns:
Expand Down Expand Up @@ -491,8 +491,8 @@ def _guess_version(self, length: 'int', **kwargs: 'Any') -> 'HTTP':
arm, or from that HTTP/2 trial, propagates unconverted.

Note:
Two things this deliberately does **not** decide, because one payload
with no flow context cannot:
This deliberately does **not** decide the following, because one
payload with no flow context cannot:

* **An** ``Upgrade: h2c`` **exchange** (:rfc:`7540#section-3.2`,
deprecated but not removed by :rfc:`9113#section-3.1`) stays
Expand All @@ -514,7 +514,7 @@ def _guess_version(self, length: 'int', **kwargs: 'Any') -> 'HTTP':
which is precisely how garbage text was classified HTTP/2 to begin
with. A bare frame is parsed as HTTP/2 only by the fall-through
below, and only if its header is one a conforming sender could
write (see :func:`_test_http2_frame`): a frame type :rfc:`9113`
write (see ``_test_http2_frame()``): a frame type :rfc:`9113`
defines, no undefined flag, and a stream that type may be sent on.
Nine zero octets -- a ``DATA`` frame on stream 0, a protocol error
under :rfc:`9113#section-6.1` -- are not guessed as HTTP/2.
Expand Down Expand Up @@ -596,7 +596,7 @@ def _guess_version(self, length: 'int', **kwargs: 'Any') -> 'HTTP':
# and no preface, and a self-consistent HTTP/2 frame is still the best
# answer available for one. It is the last resort, not the whole method.
#
# The two arms suppress different sets, deliberately. Only the *last*
# The arms of this trial suppress different sets, deliberately. Only the *last*
# arm also suppresses :exc:`struct.error`, as defence in depth: a payload
# too short for HTTP/2's nine-octet frame header, or whose frame-specific
# fields exceed what the buffer holds, must not escape as a stdlib
Expand Down
Loading
Loading