1

I'm trying to upload a CSV file using ftplib.FTP_TLS, however regardless of the timeout duration I set (5,10,60 seconds), the code always times out with the error:

File "/usr/lib/python3.4/ftplib.py", line 544, in storlines
  conn.unwrap()
File "/usr/lib/python3.4/ssl.py", line 788, in unwrap
  s = self._sslobj.shutdown()
socket.timeout: The read operation timed out

However after the timeout, I check the directory through Cyberduck, and the CSV file is there, complete.

Here is my upload code:

def upload_csv(filename):
    with FTP_TLS(timeout=5) as ftps:
        ftps.set_pasv(True)
        ftps.connect(ftps_server,ftps_port)
        ftps.login(ftps_username, ftps_password)
        ftps.prot_p()
        ftps.cwd('sales')
        ftps.storlines("STOR " + filename, open(filename,'rb'))

I've also tried storbinary(...) but get the same error.

Edit: The file definitely exists, and does actually get created on the server in its entirety. It looks like it's a problem with .shutdown() in ssl.py maybe waiting for a final read, but the internet doesn't seem to yield a solution.

Can anyone shed any light please?

Karl M.W.
  • 728
  • 5
  • 19
  • 1
    have you tried `ftps.quit()` before `.close()`? You could use `with FTP... as ftps: ..` instead of manually calling `quit`, `close`. It seems you don't need `auth()` here and you can swap `prot_p()` (encrypt data layer) and `login()` (may call `auth()` if necessary). – jfs Feb 18 '15 at 22:20
  • Thanks @J.F.Sebastian. I've updated the above code to reflect your changes which make the code much cleaner, however the problem happens in ftps.storlines. The storlines method in ftplib.py calls conn.unwrap() in ssl.py, which seems to be where the problem manifests. I could take a custom copy of ftplib.py and change the conn.unwrap() line to conn.close(), but it seems hacky... what do you think? – Karl M.W. Feb 19 '15 at 15:24
  • 1
    I don't know. Make sure that the ftplib usage is correct here (whether docs, docstrings for the methods indicate it or something stands out in an rfc). Try another Python version, other ftp clients (python or not). If you'll find a working client; trace its commands and see whether your code produces the same sequence of ftp commands (try you own ftp server to get debug logs). Try `git blame` on `unwrap()` line to see where it comes from -- in case it is a bug. – jfs Feb 19 '15 at 15:40
  • As a test I've just cloned ftplib.py and changed the conn.unwrap() line to conn.close(), and on the surface at least it seems to exit gracefully and not leave any resources open... I'll do some extra digging. Thanks for your advice and support. – Karl M.W. Feb 19 '15 at 16:05

1 Answers1

1

I was able to overcome the problem by overwriting

ftplib._SSLSocket = None

Here a more complete example:

def transfer_zip(dest_zipfile, host, host_path, user, password):
    os.chdir(dirname(dest_zipfile))
    with ftplib.FTP_TLS(host, timeout=10) as ftp:
        ftp.login(user, password)
        ftp.prot_p()
        ftp.cwd(host_path)
        ftplib._SSLSocket = None
        ftp.storbinary(f"STOR {basename(dest_zipfile)}", open(dest_zipfile, 'rb'))
        ftp.quit()
        ftp.close()
MadMike
  • 1,391
  • 1
  • 16
  • 38