From 44089d6bef8693b7d2e8875e790f12afd0046bbf Mon Sep 17 00:00:00 2001 From: C1-BA-B1-F3 Date: Fri, 26 Jun 2026 03:45:34 +0800 Subject: [PATCH] fix: improve FTPDownloadHandler connection cleanup Two improvements to the FTP connection cleanup in download_request(): 1. Store the FTPClient on self.client so that callers (and test fixtures) can access it for cleanup after the download completes. The existing dh fixture teardown already checks for dh.client to call loseConnection() as a safety net. 2. Replace assert client.transport with a safe if-check before calling loseConnection(). The assert could crash if the transport is None in edge cases (e.g. connection lost during authentication). Fixes scrapy/scrapy#7602 Co-Authored-By: Claude Opus 4.8 --- scrapy/core/downloader/handlers/ftp.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/scrapy/core/downloader/handlers/ftp.py b/scrapy/core/downloader/handlers/ftp.py index 9064aa53a..94e21920d 100644 --- a/scrapy/core/downloader/handlers/ftp.py +++ b/scrapy/core/downloader/handlers/ftp.py @@ -108,6 +108,7 @@ class FTPDownloadHandler(BaseDownloadHandler): client: FTPClient = await maybe_deferred_to_future( creator.connectTCP(parsed_url.hostname, parsed_url.port or 21) ) + self.client = client filepath = unquote(parsed_url.path) protocol = ReceivedDataProtocol(request.meta.get("ftp_local_filename")) try: @@ -121,8 +122,8 @@ class FTPDownloadHandler(BaseDownloadHandler): raise finally: protocol.close() - assert client.transport - client.transport.loseConnection() + if client.transport: + client.transport.loseConnection() headers = {"local filename": protocol.filename or b"", "size": protocol.size} body = protocol.filename or protocol.body.read() respcls = responsetypes.from_args(url=request.url, body=body)