Changeset 1671:2a3350ab9374


Ignore:
Timestamp:
Oct 8, 2017, 8:00:38 PM (14 months ago)
Author:
Stefan Schwarzer <sschwarzer@…>
Branch:
default
Message:
Handle socket read timeout in `_available_child`

When `FTPFile.close` causes a socket read timeout, the _next_ read on
the socket will raise an `OSError`. Hence, the `OSError` can happen in
the `host._session.pwd` call in `FTPHost._available_child`. Catch this
`OSError`.

Although the fix in `ftputil.host.FTPHost._available_child` will make
the child session handling work, socket read errors could result in
child sessions being returned in a non-reproducible way. To make the
identity checks in the tests reproducible, use the small `CONTENTS`
file instead of the larger `debian-keyring.tar.gz` file. Investigation
of ticket #112 showed that socket read errors would rather occur with
larger files.

This change in the tests is slightly hackish, but should be ok, unless
it'll cause other problems later on.

ticket: 112
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • ftputil/host.py

    r1636 r1671  
    175175                # when `_available_child` is called the next time.
    176176                except ftplib.error_reply:
     177                    continue
     178                # Under high load, there may be a socket read timeout
     179                # during the last FTP file `close` (see ticket #112).
     180                except OSError:
    177181                    continue
    178182                else:
  • test/test_real_ftp.py

    r1663 r1671  
    675675
    676676    def test_only_closed_children(self):
    677         REMOTE_FILE_NAME = "debian-keyring.tar.gz"
     677        REMOTE_FILE_NAME = "CONTENTS"
    678678        host = self.host
    679679        with host.open(REMOTE_FILE_NAME, "rb") as file_obj1:
     
    688688
    689689    def test_no_timed_out_children(self):
    690         REMOTE_FILE_NAME = "debian-keyring.tar.gz"
     690        REMOTE_FILE_NAME = "CONTENTS"
    691691        host = self.host
    692692        # Implicitly create child host object.
     
    706706
    707707    def test_no_delayed_226_children(self):
    708         REMOTE_FILE_NAME = "debian-keyring.tar.gz"
     708        REMOTE_FILE_NAME = "CONTENTS"
    709709        host = self.host
    710710        # Implicitly create child host object.
     
    874874    def test_subsequent_reading(self):
    875875        # Open a file for reading.
    876         with self.host.open("debian-keyring.tar.gz", "rb") as file1:
     876        with self.host.open("CONTENTS", "rb") as file1:
    877877            pass
    878878        # Make sure that there are no problems if the connection is reused.
    879         with self.host.open("debian-keyring.tar.gz", "rb") as file2:
     879        with self.host.open("CONTENTS", "rb") as file2:
    880880            pass
    881881        assert file1._session is file2._session
Note: See TracChangeset for help on using the changeset viewer.