0
# FTP Protocol Handlers
1
2
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.
3
4
## Capabilities
5
6
### Main FTP Handler
7
8
Core FTP protocol interpreter implementing the complete FTP command set with configurable behavior and extensive callback hooks for customization.
9
10
```python { .api }
11
class FTPHandler:
12
# Core configuration attributes
13
authorizer: 'Authorizer' = DummyAuthorizer()
14
active_dtp: type = 'ActiveDTP'
15
passive_dtp: type = 'PassiveDTP'
16
dtp_handler: type = 'DTPHandler'
17
abstracted_fs: type = 'AbstractedFS'
18
proto_cmds: dict = {} # FTP command definitions
19
20
# Session and security settings
21
timeout: int = 300
22
banner: str = f"pyftpdlib {__ver__} ready."
23
max_login_attempts: int = 3
24
permit_foreign_addresses: bool = False
25
permit_privileged_ports: bool = False
26
27
# Network configuration
28
masquerade_address: str = None
29
masquerade_address_map: dict = {}
30
passive_ports: range = None
31
32
# Performance settings
33
use_gmt_times: bool = True
34
use_sendfile: bool = True # Use sendfile() system call if available
35
tcp_no_delay: bool = True # Disable Nagle algorithm
36
37
# Character encoding
38
encoding: str = "utf8"
39
unicode_errors: str = 'replace'
40
41
# Logging configuration
42
log_prefix: str = '%(remote_ip)s:%(remote_port)s-[%(username)s]'
43
auth_failed_timeout: int = 3
44
45
def __init__(self, conn, server, ioloop=None):
46
"""
47
Initialize FTP session handler.
48
49
Parameters:
50
- conn: client socket connection
51
- server: FTPServer instance
52
- ioloop: IOLoop instance (optional)
53
"""
54
55
# Session management
56
def handle(self):
57
"""Send welcome banner to client."""
58
59
def handle_max_cons(self):
60
"""Handle maximum connections limit reached."""
61
62
def handle_max_cons_per_ip(self):
63
"""Handle maximum connections per IP limit reached."""
64
65
def handle_timeout(self):
66
"""Handle session timeout."""
67
68
def process_command(self, cmd, *args, **kwargs):
69
"""
70
Process FTP command from client.
71
72
Parameters:
73
- cmd: FTP command name
74
- *args: command arguments
75
- **kwargs: additional options
76
"""
77
78
def flush_account(self):
79
"""Reset user session state."""
80
81
def run_as_current_user(self, function, *args, **kwargs):
82
"""Execute function with current user privileges."""
83
84
# Connection event callbacks
85
def on_connect(self):
86
"""Called when client connects."""
87
88
def on_disconnect(self):
89
"""Called when client disconnects."""
90
91
# Authentication event callbacks
92
def on_login(self, username):
93
"""Called when user successfully logs in."""
94
95
def on_login_failed(self, username):
96
"""Called when user login fails."""
97
98
def on_logout(self, username):
99
"""Called when user logs out."""
100
101
# File transfer event callbacks
102
def on_file_sent(self, file):
103
"""Called when file transfer (RETR) completes successfully."""
104
105
def on_file_received(self, file):
106
"""Called when file transfer (STOR/APPE) completes successfully."""
107
108
def on_incomplete_file_sent(self, file):
109
"""Called when file transfer (RETR) is interrupted."""
110
111
def on_incomplete_file_received(self, file):
112
"""Called when file transfer (STOR/APPE) is interrupted."""
113
114
# Authentication commands
115
def ftp_USER(self, line):
116
"""USER command - specify username."""
117
118
def ftp_PASS(self, line):
119
"""PASS command - specify password."""
120
121
def ftp_QUIT(self, line):
122
"""QUIT command - terminate session."""
123
124
# Data connection commands
125
def ftp_PORT(self, line):
126
"""PORT command - specify client port for active mode."""
127
128
def ftp_EPRT(self, line):
129
"""EPRT command - extended PORT for IPv6."""
130
131
def ftp_PASV(self, line):
132
"""PASV command - enter passive mode."""
133
134
def ftp_EPSV(self, line):
135
"""EPSV command - extended PASV for IPv6."""
136
137
# Directory listing commands
138
def ftp_LIST(self, path):
139
"""LIST command - detailed directory listing."""
140
141
def ftp_NLST(self, path):
142
"""NLST command - name-only directory listing."""
143
144
def ftp_MLST(self, path):
145
"""MLST command - machine-readable file info."""
146
147
def ftp_MLSD(self, path):
148
"""MLSD command - machine-readable directory listing."""
149
150
# File transfer commands
151
def ftp_RETR(self, file):
152
"""RETR command - retrieve/download file."""
153
154
def ftp_STOR(self, file):
155
"""STOR command - store/upload file."""
156
157
def ftp_APPE(self, file):
158
"""APPE command - append to file."""
159
160
def ftp_STOU(self, line):
161
"""STOU command - store file with unique name."""
162
163
def ftp_REST(self, line):
164
"""REST command - set file restart position."""
165
166
def ftp_ABOR(self, line):
167
"""ABOR command - abort current transfer."""
168
169
# Directory navigation commands
170
def ftp_CWD(self, path):
171
"""CWD command - change working directory."""
172
173
def ftp_CDUP(self, path):
174
"""CDUP command - change to parent directory."""
175
176
def ftp_PWD(self, line):
177
"""PWD command - print working directory."""
178
179
# File/directory management commands
180
def ftp_MKD(self, path):
181
"""MKD command - create directory."""
182
183
def ftp_RMD(self, path):
184
"""RMD command - remove directory."""
185
186
def ftp_DELE(self, path):
187
"""DELE command - delete file."""
188
189
def ftp_RNFR(self, path):
190
"""RNFR command - rename from (source)."""
191
192
def ftp_RNTO(self, path):
193
"""RNTO command - rename to (destination)."""
194
195
# File information commands
196
def ftp_SIZE(self, path):
197
"""SIZE command - get file size."""
198
199
def ftp_MDTM(self, path):
200
"""MDTM command - get file modification time."""
201
202
def ftp_MFMT(self, path):
203
"""MFMT command - set file modification time."""
204
205
# Transfer parameter commands
206
def ftp_TYPE(self, line):
207
"""TYPE command - set transfer type (ASCII/Binary)."""
208
209
def ftp_MODE(self, line):
210
"""MODE command - set transfer mode."""
211
212
def ftp_STRU(self, line):
213
"""STRU command - set file structure."""
214
215
# Server information commands
216
def ftp_STAT(self, line):
217
"""STAT command - server/transfer status."""
218
219
def ftp_FEAT(self, line):
220
"""FEAT command - list server features."""
221
222
def ftp_HELP(self, line):
223
"""HELP command - display help information."""
224
225
# SITE commands (server-specific)
226
def ftp_SITE_CHMOD(self, path):
227
"""SITE CHMOD command - change file permissions."""
228
229
def ftp_SITE_HELP(self, line):
230
"""SITE HELP command - SITE command help."""
231
```
232
233
### SSL/TLS FTP Handler
234
235
FTP handler with SSL/TLS encryption support providing secure FTP (FTPS) capabilities with flexible security requirements.
236
237
```python { .api }
238
class TLS_FTPHandler(FTPHandler):
239
# SSL/TLS configuration
240
tls_control_required: bool = False
241
tls_data_required: bool = False
242
certfile: str = None
243
keyfile: str = None
244
ssl_protocol = None # SSL.TLS_SERVER_METHOD
245
ssl_options = None # SSL options (no SSLv2/SSLv3/compression)
246
ssl_context = None # Pre-configured SSL context
247
248
# Additional SSL/TLS commands
249
def ftp_AUTH(self, line):
250
"""AUTH command - initiate SSL/TLS handshake."""
251
252
def ftp_PBSZ(self, line):
253
"""PBSZ command - set protection buffer size."""
254
255
def ftp_PROT(self, line):
256
"""PROT command - set data channel protection level."""
257
258
def secure_connection(self, ssl_context):
259
"""Upgrade connection to SSL/TLS."""
260
261
def handle_ssl_established(self):
262
"""Called when SSL handshake completes."""
263
264
def handle_ssl_shutdown(self):
265
"""Called when SSL connection shuts down."""
266
267
def handle_failed_ssl_handshake(self):
268
"""Called when SSL handshake fails."""
269
```
270
271
### Data Transfer Protocol Handlers
272
273
Classes managing FTP data connections for file transfers, supporting both active and passive modes with optional SSL/TLS encryption.
274
275
```python { .api }
276
class DTPHandler:
277
# Transfer configuration
278
timeout: int = 300
279
ac_in_buffer_size: int = 65536
280
ac_out_buffer_size: int = 65536
281
282
def __init__(self, sock, cmd_channel):
283
"""
284
Initialize data transfer handler.
285
286
Parameters:
287
- sock: data connection socket
288
- cmd_channel: associated FTP command channel
289
"""
290
291
def use_sendfile(self):
292
"""Check if sendfile() optimization can be used."""
293
294
def push(self, data):
295
"""Send data to client."""
296
297
def push_with_producer(self, producer):
298
"""Send data using producer pattern."""
299
300
def enable_receiving(self, type, cmd):
301
"""Enable data receiving mode for uploads."""
302
303
def get_transmitted_bytes(self):
304
"""Get number of bytes transferred."""
305
306
def get_elapsed_time(self):
307
"""Get transfer duration in seconds."""
308
309
def transfer_in_progress(self):
310
"""Check if transfer is currently active."""
311
312
def handle_read(self):
313
"""Handle incoming data during upload."""
314
315
def handle_timeout(self):
316
"""Handle stalled transfer timeout."""
317
318
def close(self):
319
"""Close data connection and cleanup."""
320
321
class ThrottledDTPHandler(DTPHandler):
322
# Bandwidth limiting
323
read_limit: int = 0 # Max read bytes/sec (0 = unlimited)
324
write_limit: int = 0 # Max write bytes/sec (0 = unlimited)
325
auto_sized_buffers: bool = True
326
327
class TLS_DTPHandler(DTPHandler):
328
"""SSL/TLS enabled data transfer handler."""
329
330
class PassiveDTP:
331
timeout: int = 30
332
backlog: int = None
333
334
def __init__(self, cmd_channel, extmode=False):
335
"""Initialize passive data connection listener."""
336
337
def handle_accepted(self, sock, addr):
338
"""Handle client connection to passive port."""
339
340
class ActiveDTP:
341
timeout: int = 30
342
343
def __init__(self, ip, port, cmd_channel):
344
"""Initialize active data connection to client."""
345
346
def handle_connect(self):
347
"""Handle successful connection to client."""
348
```
349
350
### Data Producers
351
352
Producer classes for efficient file transfer using the producer/consumer pattern.
353
354
```python { .api }
355
class FileProducer:
356
buffer_size: int = 65536
357
358
def __init__(self, file, type):
359
"""
360
Initialize file producer.
361
362
Parameters:
363
- file: file object to read from
364
- type: transfer type ('i' for binary, 'a' for ASCII)
365
"""
366
367
def more(self):
368
"""Read and return next chunk of file data."""
369
370
class BufferedIteratorProducer:
371
loops: int = 20
372
373
def __init__(self, iterator):
374
"""Initialize producer from iterator."""
375
376
def more(self):
377
"""Get next batch from iterator."""
378
```
379
380
## Exception Classes
381
382
```python { .api }
383
class _FileReadWriteError(OSError):
384
"""File read/write errors during transfer."""
385
386
class _GiveUpOnSendfile(Exception):
387
"""Fallback from sendfile() to regular send()."""
388
```
389
390
## Constants
391
392
```python { .api }
393
CR_BYTE: int # Carriage return byte value
394
proto_cmds: dict # FTP command definitions with properties
395
```
396
397
## Usage Examples
398
399
### Basic FTP Handler Setup
400
401
```python
402
from pyftpdlib.handlers import FTPHandler
403
from pyftpdlib.authorizers import DummyAuthorizer
404
405
# Configure authorizer
406
authorizer = DummyAuthorizer()
407
authorizer.add_user("user", "pass", "/home/user", perm="elradfmwMT")
408
409
# Configure handler
410
handler = FTPHandler
411
handler.authorizer = authorizer
412
handler.banner = "Welcome to my FTP server"
413
handler.timeout = 600
414
```
415
416
### SSL/TLS FTP Server
417
418
```python
419
from pyftpdlib.handlers import TLS_FTPHandler
420
421
class MyTLS_FTPHandler(TLS_FTPHandler):
422
certfile = "/path/to/certificate.pem"
423
keyfile = "/path/to/private_key.pem"
424
tls_control_required = True
425
tls_data_required = True
426
427
handler = MyTLS_FTPHandler
428
handler.authorizer = authorizer
429
```
430
431
### Custom Handler with Callbacks
432
433
```python
434
class CustomFTPHandler(FTPHandler):
435
def on_connect(self):
436
print(f"Client connected from {self.remote_ip}")
437
438
def on_login(self, username):
439
print(f"User {username} logged in successfully")
440
441
def on_file_sent(self, file):
442
print(f"File {file} sent to {self.username}")
443
444
def on_file_received(self, file):
445
print(f"File {file} received from {self.username}")
446
447
def on_logout(self, username):
448
print(f"User {username} logged out")
449
450
handler = CustomFTPHandler
451
handler.authorizer = authorizer
452
```
453
454
### Performance Optimization
455
456
```python
457
class OptimizedFTPHandler(FTPHandler):
458
# Enable performance optimizations
459
use_sendfile = True # Use sendfile() for uploads
460
tcp_no_delay = True # Disable Nagle algorithm
461
462
# Configure timeouts
463
timeout = 300 # 5 minute session timeout
464
auth_failed_timeout = 1 # Fast auth failure response
465
466
# Buffer sizes for data transfers
467
dtp_handler = ThrottledDTPHandler
468
469
# Configure bandwidth limits
470
class BandwidthLimitedDTPHandler(ThrottledDTPHandler):
471
read_limit = 1024 * 100 # 100 KB/s download limit
472
write_limit = 1024 * 50 # 50 KB/s upload limit
473
474
handler = OptimizedFTPHandler
475
handler.dtp_handler = BandwidthLimitedDTPHandler
476
```
477
478
### Network Configuration
479
480
```python
481
class NetworkConfiguredHandler(FTPHandler):
482
# NAT/Firewall configuration
483
masquerade_address = "203.0.113.10" # External IP for PASV
484
passive_ports = range(50000, 50099) # PASV port range
485
permit_foreign_addresses = False # Block FXP transfers
486
permit_privileged_ports = False # Block privileged ports
487
488
handler = NetworkConfiguredHandler
489
handler.authorizer = authorizer
490
```
491
492
### Logging Configuration
493
494
```python
495
class LoggingFTPHandler(FTPHandler):
496
log_prefix = '[%(asctime)s] %(remote_ip)s:%(remote_port)s-[%(username)s]'
497
498
def process_command(self, cmd, *args, **kwargs):
499
print(f"Command: {cmd} {' '.join(args) if args else ''}")
500
return super().process_command(cmd, *args, **kwargs)
501
502
handler = LoggingFTPHandler
503
handler.authorizer = authorizer
504
```
505
506
### Custom Command Implementation
507
508
```python
509
class ExtendedFTPHandler(FTPHandler):
510
def ftp_SITE_USAGE(self, line):
511
"""Custom SITE USAGE command."""
512
# Implementation here
513
self.respond("200 Disk usage: 50% of 1TB")
514
515
# Add to proto_cmds to register command
516
proto_cmds = FTPHandler.proto_cmds.copy()
517
proto_cmds['SITE USAGE'] = dict(
518
perm=None, auth=True, help='Syntax: SITE USAGE (show disk usage)'
519
)
520
521
handler = ExtendedFTPHandler
522
handler.authorizer = authorizer
523
```