I am attempting to upload zip files to ShareFile with python code but I am finding the code hangs in an overridden version of ftplib.FTP_TLS.storebinary() in a class inheriting from FTP_TLs and does not return until a ssl.SSLError exception is thrown. The file is uploaded and appears intact before the exception occurs.
Runtime error
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "C:\Python27\ArcGIS10.2\Lib\ftplib.py", line 741, in storbinary
conn.unwrap()
File "C:\Python27\ArcGIS10.2\Lib\ssl.py", line 284, in unwrap
s = self._sslobj.shutdown()
SSLError: The read operation timed out
Why does this happen and is there a way I can fix this so I get the FTP server message instead of timing out?
ShareFile requires Implicit FTP (port 990, encrypted control and data channels) and this is not implemented in Python's ftplib but I did find some handy code here on Stack Overflow (Python FTP implicit TLS connection issue.) while researching the problem. After testing I returned to this Stackoverflow question but could not find an answer to the timeout problem. My area of expertise is with Geographical Information Systems (GIS) so I am out of my comfort zone with sockets and FTP protocol.
At the moment I am using test code with Python 2.7.5 embedded in software called ArcMap but intend to use the final code with Python embedded in alternative software called FME 2014, also using Python 2.7.5. FME will generate zip files of spatial data and a Python shut-down script will upload the data. Upgrading to Python 2.7.10 is not an option due to ICT workloads and priorities.
The code I am using is listed below:
#---------------------------------
# Code by Juan Moreno, answer 3 in https://stackoverflow.com/questions/12164470/python-ftp-tls-connection-issue#
#---------------------------------
from ftplib import FTP_TLS, FTP
import socket
import ssl
class IMPLICIT_FTP_TLS(FTP_TLS):
def __init__(self, host='', user='', passwd='', acct='', keyfile=None, certfile=None, timeout=60):
FTP_TLS.__init__(self, host, user, passwd, acct, keyfile, certfile, timeout)
def connect(self, host='', port=0, timeout=-999): ### FTP.connect(host[, port[, timeout]])
if host != '':
self.host = host
if port > 0:
self.port = port
if timeout != -999:
self.timeout = timeout
try:
self.sock = socket.create_connection((self.host, self.port), self.timeout)
self.af = self.sock.family
self.sock = ssl.wrap_socket(self.sock, self.keyfile, self.certfile)
self.file = self.sock.makefile('rb')
self.welcome = self.getresp()
except Exception as e:
print e
return self.welcome
def ntransfercmd(self, cmd, rest=None):
conn, size = FTP.ntransfercmd(self, cmd, rest)
if self._prot_p:
conn = ssl.wrap_socket(conn, self.keyfile, self.certfile)
return conn, size
My test code
import os
#----------------------------------
# test Code using IMPLICIT_FTP_TLS
#----------------------------------
ftps = IMPLICIT_FTP_TLS()
try:
print "conn: {}".format( ftps.connect(host="myorg.sharefileftp.com", port=990, timeout=5) )
print "login: {}".format( ftps.login(user="myorg/me@myorgdomain", passwd="****") )
print "prot_p: {}".format( ftps.prot_p() )
print "cwd: {}".format( ftps.cwd("me@myorgdomain") )
print "cwd: {}".format( ftps.cwd("myfolder") )
filename = r"C:\project\datafile.zip"
print "attempting to upload data..."
with open(filename, "rb") as myzipfile:
print "storB: {}".format( ftps.storbinary("STOR {}".format(os.path.basename(filename)), myzipfile) )
except ssl.SSLError as sslerr:
print sslerr
print "args: {}".format(sslerr.args)
except StandardError as se:
print se
finally:
print "quit: {}".format( ftps.quit() )
del ftps
Thank you for spending the time to read this and hopefully answer.