2

I'm trying to transfer a file using Python's ftplib.

def ftps_put_file(host, user, password, ftp_file_path, processed_file):
    try:
        context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH, cafile='C:\\PATH\\TO\\SECURE.crt')
        with FTP_TLS(host, user=user, passwd=password, context=context, timeout=10) as connection, open(processed_file, 'rb') as read_file:
            connection.set_debuglevel(2)
            connection.prot_p()
            connection.cwd(ftp_file_path)
            connection.storbinary(f"STOR {processed_file.name}", read_file)
    except Exception as e:
        print('Error occured in transporter.ftps_put_file: ' + str(e))

I can connect to the FTP host without any issues, but during the file transfer. The connection timeout kicks in and closes the connection, then the log for the connection says it '425 Data channel timed out due to not meeting the minimum bandwidth requirement.' I've used other FTP clients (Filezilla, WinSCP) and both are able to connect to the host.

Log with connection timeout set to 2 minutes

*cmd* 'PBSZ 0'
*put* 'PBSZ 0\r\n'
*get* '200 PBSZ command successful.\n'
*resp* '200 PBSZ command successful.'
*cmd* 'PROT P'
*put* 'PROT P\r\n'
*get* '200 PROT command successful.\n'
*resp* '200 PROT command successful.'
*cmd* 'CWD /'
*put* 'CWD /\r\n'
*get* '250 CWD command successful.\n'
*resp* '250 CWD command successful.'
*cmd* 'TYPE I'
*put* 'TYPE I\r\n'
*get* '200 Type set to I.\n'
*resp* '200 Type set to I.'
*cmd* 'PASV'
*put* 'PASV\r\n'
*get* '227 Entering Passive Mode (204,58,62,196,19,199).\n'
*resp* '227 Entering Passive Mode (204,58,62,196,19,199).'
*cmd* 'STOR text.txt'
*put* 'STOR text.txt\r\n'
*get* '125 Data connection already open; Transfer starting.\n'
*resp* '125 Data connection already open; Transfer starting.'
*cmd* 'QUIT'
*put* 'QUIT\r\n'
*get* '425 Data channel timed out due to not meeting the minimum bandwidth requirement.\n'
*resp* '425 Data channel timed out due to not meeting the minimum bandwidth requirement.'

Log with connection timeout set to 60 seconds or less The sequence with this one seems weird because the connection quits then gives a 226 Transfer Completed. Shouldn't it state that the transfer completed then quit?

*cmd* 'PBSZ 0'
*put* 'PBSZ 0\r\n'
*get* '200 PBSZ command successful.\n'
*resp* '200 PBSZ command successful.'
*cmd* 'PROT P'
*put* 'PROT P\r\n'
*get* '200 PROT command successful.\n'
*resp* '200 PROT command successful.'
*cmd* 'CWD /'
*put* 'CWD /\r\n'
*get* '250 CWD command successful.\n'
*resp* '250 CWD command successful.'
*cmd* 'TYPE I'
*put* 'TYPE I\r\n'
*get* '200 Type set to I.\n'
*resp* '200 Type set to I.'
*cmd* 'PASV'
*put* 'PASV\r\n'
*get* '227 Entering Passive Mode (204,58,62,196,20,46).\n'
*resp* '227 Entering Passive Mode (204,58,62,196,20,46).'
*cmd* 'STOR text.txt'
*put* 'STOR text.txt\r\n'
*get* '125 Data connection already open; Transfer starting.\n'
*resp* '125 Data connection already open; Transfer starting.'
*cmd* 'QUIT'
*put* 'QUIT\r\n'
*get* '226 Transfer complete.\n'
*resp* '226 Transfer complete.'
Jade Cowan
  • 2,543
  • 1
  • 18
  • 32
  • Uh, wow! Thank you for taking the time to help me with this. Didn't expect to get THE guy who wrote WinSCP. Here's a link to the WinSCP log https://pastebin.com/raw/h6Y4Wi2v. I obfuscated some stuff, but I think you'll get the idea. I only notice the 425 error when I set the connection timeout to 2 minutes (nothing is transferred when this happens). If the timeout is set to say 60 seconds or less, the transfer is successful, but the connection still throws an error and the log sequence seems weird (see edit) – Jade Cowan Sep 30 '19 at 18:24
  • Right. When the timeout is a minute or less it is transferred. It's just odd that the connection still throws an error. – Jade Cowan Sep 30 '19 at 18:47
  • See also [ftplib storbinary with FTPS is hanging/never completing](https://stackoverflow.com/q/50115522/850848). – Martin Prikryl Jan 24 '22 at 13:12

2 Answers2

1

I am experiencing the same problem. My options to debug the communication are limited (not full access to client, no access to server), but it seems to me that the server side is not sending an acknowledgement when the client closes the connection (as described here -- https://enterprisedt.com/questions/index.php/2580/ftpexception-425-data-channel-timed-out-due-to-not-meeting?start=10)

I am using Linux Python 3.7 standard library (ftplib.FTP_TLS) on the client side and there is Windows FTP service on the server side.

There is no satisfactory solution for me right now, I just make sure the file is uploaded correctly by checking the uploaded file size. I have been told that FileZilla client on Windows treats this correctly (ie. without errors, but I am unable to verify).

bubak
  • 1,464
  • 1
  • 13
  • 11
1

If your are using MS FTP(S) server there is a hack to this involving commenting some code in storbinary function in ftplib.py library.

I was having the same issue when I saw this in this SO solution/hack ftplib storbinary with FTPS is hanging/never completing. It works for me, thankfully!

Basically, you just need to make sure you don't call conn.unwrap in here.

lib/ftplib.py

#shutdown ssl layer
if isinstance(conn, ssl.SSLSocket):
    pass #conn.unwrap()
Francisco
  • 11
  • 1