5

I'm looking into using ftplib (and possibly ftputil) for doing some automated FTP file syncing. I have a couple of servers to test this against at the moment, but, whilst I'm having a successful conversation with both servers, I get EOFError-s with each error reply. For example: if I try to log in with an incorrect user/pass, I will get the 530 response with everything... but I also get an EOFError; if I login with a correct user/pass or try to dir() after doing so etc., I get no EOFError.

It seems to only appear with error messages. I strongly suspect this may be caused by the servers rather than python: I've not found any mention of this issue elsewhere. I, however, have very little control over the server setup.

I'm asking for ideas:

  • Do you know what could be causing the error in the first place?
  • If it's server-side, could you be more specific? I won't know if I'll be able to do anything about it until I know what it is...
  • How do you think I should handle this? I guess I could add an except EOFError: pass before each time I handle an exception, but if you have better/neater ideas I would love to hear them.

Thanks!

VisioN
  • 143,310
  • 32
  • 282
  • 281
bdeniker
  • 995
  • 1
  • 9
  • 21

1 Answers1

6

The servers are sending EOF to tell you that they've terminated the connection.

You should treat this no differently than any other disconnection event, except that obviously you need to handle it with except EOFError.

See the source, from http://svn.python.org/view/python/trunk/Lib/ftplib.py?view=markup

# Internal: return one line from the server, stripping CRLF.
# Raise EOFError if the connection is closed
182     def getline(self):
183         line = self.file.readline()
184         if self.debugging > 1:
185             print '*get*', self.sanitize(line)
186         if not line: raise EOFError
187         if line[-2:] == CRLF: line = line[:-2]
188         elif line[-1:] in CRLF: line = line[:-1]
189         return line

EOFError is only raised when readline() on the connection returns a blank line, which the comment indicates is a disconnection event.

Edit in re your comment:

The server doesn't send an empty line. readline() returns everything up to the next \n or \r or \r\n or all of the abouve depending on how it's configured. In this case, there is nothing to read because the end of the file has been reached. This causes readline() to return a blank line, it doesn't mean a blank line has been read. If a blank line had been read, readline() would return the character that ended the line (\n or \r or \n\r).

If you don't get the exception when using FTPUtil, that is because it handles it internally.

agf
  • 171,228
  • 44
  • 289
  • 238
  • I don't think they are... I can log in, get a directory listing, try to create a directory I don't have permissions to create (and get and `EOFerror` along with the `error_perm`), then `dir()` _again_ on the same connection object successfully. Shouldn't I not be able to do the latter (or at least need to re-log-in) if it had closed the connection? – bdeniker Jul 25 '11 at 15:43
  • 1
    I think there may be two levels of connection -- each request and response is essentially one connection, while the control channel is essentially another connection. This `EOF` happens after every command (I think), but it only bubbles up to you when the command was an error. – agf Jul 25 '11 at 16:05
  • I suppose so, but I still don't really know why the sever sends an empty line with exceptions... On top of that, [`ftputil`](http://pypi.python.org/pypi/ftputil/2.4.1) gives me only the relevant exception, even though it appears to use `ftplib`... – bdeniker Jul 26 '11 at 15:14
  • Thanks for explaining it step-by-step :) I still think it's somewhat weird behaviour, but it's probably some unfortunate synergy between this library and the server I'm connecting to... Thanks again. – bdeniker Jul 26 '11 at 15:32