Closed AllSeeingEyeTolledEweSew closed 4 years ago
Nice, and I appreciate the extra effort re. the unit tests. I would only ask a change: to do fileno() and try/except in the class constructor (more performant as sendfile() is called repeatedly).
(sent from my phone so I will get a better look soon)
Updated. I moved it to use_sendfile()
. Has the additional benefit that it doesn't generate a log warning in this case.
Currently, pyftpdlib tests for
sendfile()
support on a file object by testing for the existence of afileno
attribute. This is appropriate for some abstract IO objects likeBytesIO
.However, for complex IO objects which inherit from
io.IOBase
, thefileno()
method always exists but raisesio.UnsupportedOperation
when called. pyftpdlib thinks the object supports sendfile but crashes when calling the method.(the
io
module APIs are a convoluted mess, which creates this confusion in the first place, but it's also why inheriting from their base objects is the most reliable way to ensure conformance)My use case is that I'm writing an FTP server that accesses bittorrent data downloaded on demand, instead of the server's filesystem. I do this by creating objects which inherit from
io.BufferedIOBase
and feeding them to pyftpdlib. Currently, I need to disable sendfile globally by settinghandler.use_sendfile = False
. This is fine for now, but I will likely want to intermix sendfile- and non-sendfile IO objects in the future, due to some variance in how I can access data from libtorrent.This fix just puts the call to
fileno()
inside the try-except around sendfile, so it can use the fallback to regular send.