Very fast asynchronous FTP server library providing RFC-959 compliant FTP servers with advanced features including FTPS, IPv6, Unicode support, and flexible authentication systems
—
Main FTP protocol implementation providing comprehensive RFC-959 compliant FTP server functionality with 40+ FTP commands, SSL/TLS encryption, data transfer management, and extensive customization options through callback hooks and configurable parameters.
Core FTP protocol interpreter implementing the complete FTP command set with configurable behavior and extensive callback hooks for customization.
class FTPHandler:
# Core configuration attributes
authorizer: 'Authorizer' = DummyAuthorizer()
active_dtp: type = 'ActiveDTP'
passive_dtp: type = 'PassiveDTP'
dtp_handler: type = 'DTPHandler'
abstracted_fs: type = 'AbstractedFS'
proto_cmds: dict = {} # FTP command definitions
# Session and security settings
timeout: int = 300
banner: str = f"pyftpdlib {__ver__} ready."
max_login_attempts: int = 3
permit_foreign_addresses: bool = False
permit_privileged_ports: bool = False
# Network configuration
masquerade_address: str = None
masquerade_address_map: dict = {}
passive_ports: range = None
# Performance settings
use_gmt_times: bool = True
use_sendfile: bool = True # Use sendfile() system call if available
tcp_no_delay: bool = True # Disable Nagle algorithm
# Character encoding
encoding: str = "utf8"
unicode_errors: str = 'replace'
# Logging configuration
log_prefix: str = '%(remote_ip)s:%(remote_port)s-[%(username)s]'
auth_failed_timeout: int = 3
def __init__(self, conn, server, ioloop=None):
"""
Initialize FTP session handler.
Parameters:
- conn: client socket connection
- server: FTPServer instance
- ioloop: IOLoop instance (optional)
"""
# Session management
def handle(self):
"""Send welcome banner to client."""
def handle_max_cons(self):
"""Handle maximum connections limit reached."""
def handle_max_cons_per_ip(self):
"""Handle maximum connections per IP limit reached."""
def handle_timeout(self):
"""Handle session timeout."""
def process_command(self, cmd, *args, **kwargs):
"""
Process FTP command from client.
Parameters:
- cmd: FTP command name
- *args: command arguments
- **kwargs: additional options
"""
def flush_account(self):
"""Reset user session state."""
def run_as_current_user(self, function, *args, **kwargs):
"""Execute function with current user privileges."""
# Connection event callbacks
def on_connect(self):
"""Called when client connects."""
def on_disconnect(self):
"""Called when client disconnects."""
# Authentication event callbacks
def on_login(self, username):
"""Called when user successfully logs in."""
def on_login_failed(self, username):
"""Called when user login fails."""
def on_logout(self, username):
"""Called when user logs out."""
# File transfer event callbacks
def on_file_sent(self, file):
"""Called when file transfer (RETR) completes successfully."""
def on_file_received(self, file):
"""Called when file transfer (STOR/APPE) completes successfully."""
def on_incomplete_file_sent(self, file):
"""Called when file transfer (RETR) is interrupted."""
def on_incomplete_file_received(self, file):
"""Called when file transfer (STOR/APPE) is interrupted."""
# Authentication commands
def ftp_USER(self, line):
"""USER command - specify username."""
def ftp_PASS(self, line):
"""PASS command - specify password."""
def ftp_QUIT(self, line):
"""QUIT command - terminate session."""
# Data connection commands
def ftp_PORT(self, line):
"""PORT command - specify client port for active mode."""
def ftp_EPRT(self, line):
"""EPRT command - extended PORT for IPv6."""
def ftp_PASV(self, line):
"""PASV command - enter passive mode."""
def ftp_EPSV(self, line):
"""EPSV command - extended PASV for IPv6."""
# Directory listing commands
def ftp_LIST(self, path):
"""LIST command - detailed directory listing."""
def ftp_NLST(self, path):
"""NLST command - name-only directory listing."""
def ftp_MLST(self, path):
"""MLST command - machine-readable file info."""
def ftp_MLSD(self, path):
"""MLSD command - machine-readable directory listing."""
# File transfer commands
def ftp_RETR(self, file):
"""RETR command - retrieve/download file."""
def ftp_STOR(self, file):
"""STOR command - store/upload file."""
def ftp_APPE(self, file):
"""APPE command - append to file."""
def ftp_STOU(self, line):
"""STOU command - store file with unique name."""
def ftp_REST(self, line):
"""REST command - set file restart position."""
def ftp_ABOR(self, line):
"""ABOR command - abort current transfer."""
# Directory navigation commands
def ftp_CWD(self, path):
"""CWD command - change working directory."""
def ftp_CDUP(self, path):
"""CDUP command - change to parent directory."""
def ftp_PWD(self, line):
"""PWD command - print working directory."""
# File/directory management commands
def ftp_MKD(self, path):
"""MKD command - create directory."""
def ftp_RMD(self, path):
"""RMD command - remove directory."""
def ftp_DELE(self, path):
"""DELE command - delete file."""
def ftp_RNFR(self, path):
"""RNFR command - rename from (source)."""
def ftp_RNTO(self, path):
"""RNTO command - rename to (destination)."""
# File information commands
def ftp_SIZE(self, path):
"""SIZE command - get file size."""
def ftp_MDTM(self, path):
"""MDTM command - get file modification time."""
def ftp_MFMT(self, path):
"""MFMT command - set file modification time."""
# Transfer parameter commands
def ftp_TYPE(self, line):
"""TYPE command - set transfer type (ASCII/Binary)."""
def ftp_MODE(self, line):
"""MODE command - set transfer mode."""
def ftp_STRU(self, line):
"""STRU command - set file structure."""
# Server information commands
def ftp_STAT(self, line):
"""STAT command - server/transfer status."""
def ftp_FEAT(self, line):
"""FEAT command - list server features."""
def ftp_HELP(self, line):
"""HELP command - display help information."""
# SITE commands (server-specific)
def ftp_SITE_CHMOD(self, path):
"""SITE CHMOD command - change file permissions."""
def ftp_SITE_HELP(self, line):
"""SITE HELP command - SITE command help."""FTP handler with SSL/TLS encryption support providing secure FTP (FTPS) capabilities with flexible security requirements.
class TLS_FTPHandler(FTPHandler):
# SSL/TLS configuration
tls_control_required: bool = False
tls_data_required: bool = False
certfile: str = None
keyfile: str = None
ssl_protocol = None # SSL.TLS_SERVER_METHOD
ssl_options = None # SSL options (no SSLv2/SSLv3/compression)
ssl_context = None # Pre-configured SSL context
# Additional SSL/TLS commands
def ftp_AUTH(self, line):
"""AUTH command - initiate SSL/TLS handshake."""
def ftp_PBSZ(self, line):
"""PBSZ command - set protection buffer size."""
def ftp_PROT(self, line):
"""PROT command - set data channel protection level."""
def secure_connection(self, ssl_context):
"""Upgrade connection to SSL/TLS."""
def handle_ssl_established(self):
"""Called when SSL handshake completes."""
def handle_ssl_shutdown(self):
"""Called when SSL connection shuts down."""
def handle_failed_ssl_handshake(self):
"""Called when SSL handshake fails."""Classes managing FTP data connections for file transfers, supporting both active and passive modes with optional SSL/TLS encryption.
class DTPHandler:
# Transfer configuration
timeout: int = 300
ac_in_buffer_size: int = 65536
ac_out_buffer_size: int = 65536
def __init__(self, sock, cmd_channel):
"""
Initialize data transfer handler.
Parameters:
- sock: data connection socket
- cmd_channel: associated FTP command channel
"""
def use_sendfile(self):
"""Check if sendfile() optimization can be used."""
def push(self, data):
"""Send data to client."""
def push_with_producer(self, producer):
"""Send data using producer pattern."""
def enable_receiving(self, type, cmd):
"""Enable data receiving mode for uploads."""
def get_transmitted_bytes(self):
"""Get number of bytes transferred."""
def get_elapsed_time(self):
"""Get transfer duration in seconds."""
def transfer_in_progress(self):
"""Check if transfer is currently active."""
def handle_read(self):
"""Handle incoming data during upload."""
def handle_timeout(self):
"""Handle stalled transfer timeout."""
def close(self):
"""Close data connection and cleanup."""
class ThrottledDTPHandler(DTPHandler):
# Bandwidth limiting
read_limit: int = 0 # Max read bytes/sec (0 = unlimited)
write_limit: int = 0 # Max write bytes/sec (0 = unlimited)
auto_sized_buffers: bool = True
class TLS_DTPHandler(DTPHandler):
"""SSL/TLS enabled data transfer handler."""
class PassiveDTP:
timeout: int = 30
backlog: int = None
def __init__(self, cmd_channel, extmode=False):
"""Initialize passive data connection listener."""
def handle_accepted(self, sock, addr):
"""Handle client connection to passive port."""
class ActiveDTP:
timeout: int = 30
def __init__(self, ip, port, cmd_channel):
"""Initialize active data connection to client."""
def handle_connect(self):
"""Handle successful connection to client."""Producer classes for efficient file transfer using the producer/consumer pattern.
class FileProducer:
buffer_size: int = 65536
def __init__(self, file, type):
"""
Initialize file producer.
Parameters:
- file: file object to read from
- type: transfer type ('i' for binary, 'a' for ASCII)
"""
def more(self):
"""Read and return next chunk of file data."""
class BufferedIteratorProducer:
loops: int = 20
def __init__(self, iterator):
"""Initialize producer from iterator."""
def more(self):
"""Get next batch from iterator."""class _FileReadWriteError(OSError):
"""File read/write errors during transfer."""
class _GiveUpOnSendfile(Exception):
"""Fallback from sendfile() to regular send()."""CR_BYTE: int # Carriage return byte value
proto_cmds: dict # FTP command definitions with propertiesfrom pyftpdlib.handlers import FTPHandler
from pyftpdlib.authorizers import DummyAuthorizer
# Configure authorizer
authorizer = DummyAuthorizer()
authorizer.add_user("user", "pass", "/home/user", perm="elradfmwMT")
# Configure handler
handler = FTPHandler
handler.authorizer = authorizer
handler.banner = "Welcome to my FTP server"
handler.timeout = 600from pyftpdlib.handlers import TLS_FTPHandler
class MyTLS_FTPHandler(TLS_FTPHandler):
certfile = "/path/to/certificate.pem"
keyfile = "/path/to/private_key.pem"
tls_control_required = True
tls_data_required = True
handler = MyTLS_FTPHandler
handler.authorizer = authorizerclass CustomFTPHandler(FTPHandler):
def on_connect(self):
print(f"Client connected from {self.remote_ip}")
def on_login(self, username):
print(f"User {username} logged in successfully")
def on_file_sent(self, file):
print(f"File {file} sent to {self.username}")
def on_file_received(self, file):
print(f"File {file} received from {self.username}")
def on_logout(self, username):
print(f"User {username} logged out")
handler = CustomFTPHandler
handler.authorizer = authorizerclass OptimizedFTPHandler(FTPHandler):
# Enable performance optimizations
use_sendfile = True # Use sendfile() for uploads
tcp_no_delay = True # Disable Nagle algorithm
# Configure timeouts
timeout = 300 # 5 minute session timeout
auth_failed_timeout = 1 # Fast auth failure response
# Buffer sizes for data transfers
dtp_handler = ThrottledDTPHandler
# Configure bandwidth limits
class BandwidthLimitedDTPHandler(ThrottledDTPHandler):
read_limit = 1024 * 100 # 100 KB/s download limit
write_limit = 1024 * 50 # 50 KB/s upload limit
handler = OptimizedFTPHandler
handler.dtp_handler = BandwidthLimitedDTPHandlerclass NetworkConfiguredHandler(FTPHandler):
# NAT/Firewall configuration
masquerade_address = "203.0.113.10" # External IP for PASV
passive_ports = range(50000, 50099) # PASV port range
permit_foreign_addresses = False # Block FXP transfers
permit_privileged_ports = False # Block privileged ports
handler = NetworkConfiguredHandler
handler.authorizer = authorizerclass LoggingFTPHandler(FTPHandler):
log_prefix = '[%(asctime)s] %(remote_ip)s:%(remote_port)s-[%(username)s]'
def process_command(self, cmd, *args, **kwargs):
print(f"Command: {cmd} {' '.join(args) if args else ''}")
return super().process_command(cmd, *args, **kwargs)
handler = LoggingFTPHandler
handler.authorizer = authorizerclass ExtendedFTPHandler(FTPHandler):
def ftp_SITE_USAGE(self, line):
"""Custom SITE USAGE command."""
# Implementation here
self.respond("200 Disk usage: 50% of 1TB")
# Add to proto_cmds to register command
proto_cmds = FTPHandler.proto_cmds.copy()
proto_cmds['SITE USAGE'] = dict(
perm=None, auth=True, help='Syntax: SITE USAGE (show disk usage)'
)
handler = ExtendedFTPHandler
handler.authorizer = authorizerInstall with Tessl CLI
npx tessl i tessl/pypi-pyftpdlib