Source code for pcapkit.protocols.application.ftp
# -*- coding: utf-8 -*-
"""file transfer protocol
:mod:`pcapkit.protocols.application.ftp` contains
:class:`~pcapkit.protocols.application.ftp.FTP` only,
which implements extractor for File Transfer Protocol
(FTP) [*]_.
.. [*] https://en.wikipedia.org/wiki/File_Transfer_Protocol
"""
import re
from typing import TYPE_CHECKING
from pcapkit.const.ftp.command import Command
from pcapkit.const.ftp.return_code import ReturnCode
from pcapkit.protocols.application.application import Application
from pcapkit.protocols.data.application.ftp import FTP as DataType_FTP
from pcapkit.protocols.data.application.ftp import Request as DataType_Request
from pcapkit.protocols.data.application.ftp import Response as DataType_Response
from pcapkit.utilities.exceptions import ProtocolError, UnsupportedCall
if TYPE_CHECKING:
from typing import Any, NoReturn, Optional
from typing_extensions import Literal
__all__ = ['FTP']
[docs]class FTP(Application[DataType_FTP]):
"""This class implements File Transfer Protocol."""
##########################################################################
# Properties.
##########################################################################
@property
def name(self) -> 'Literal["File Transfer Protocol"]':
"""Name of current protocol."""
return 'File Transfer Protocol'
@property
def length(self) -> 'NoReturn':
"""Header length of current protocol.
Raises:
UnsupportedCall: This protocol doesn't support :attr:`length`.
"""
raise UnsupportedCall(f"'{self.__class__.__name__}' object has no attribute 'length'")
##########################################################################
# Methods.
##########################################################################
[docs] def read(self, length: 'Optional[int]' = None, **kwargs: 'Any') -> 'DataType_FTP': # pylint: disable=unused-argument
"""Read File Transfer Protocol (FTP).
Args:
length: Length of packet data.
**kwargs: Arbitrary keyword arguments.
Returns:
Parsed packet data.
Raises:
ProtocolError: If the packet is malformed.
"""
if length is None:
length = len(self)
byte = self._read_fileng(length)
if (not byte.endswith(b'\r\n')) or (len(byte.splitlines()) > 1):
raise ProtocolError('FTP: invalid format')
text = self.decode(byte.strip())
if TYPE_CHECKING:
pref: 'int | str'
ftp: 'DataType_Request | DataType_Response'
if re.match(r'^\d{3}', text):
pref = int(text[:3])
try:
flag = text[3] == '-'
except IndexError:
flag = False
suff = text[4:] or None
code = ReturnCode.get(pref)
ftp = DataType_Response(
type='response',
code=code,
arg=suff,
mf=flag,
raw=byte,
)
else:
temp = text.split(maxsplit=1)
if len(temp) == 2:
pref, suff = temp
else:
pref, suff = text, None
cmmd = Command[pref]
ftp = DataType_Request(
type='request',
command=cmmd,
arg=suff,
raw=byte,
)
return ftp
[docs] def make(self, **kwargs: 'Any') -> 'NoReturn':
"""Make (construct) packet data.
Args:
Arbitrary keyword arguments.
Returns:
Constructed packet data.
"""
raise NotImplementedError