From 0d4dfae494c3b5c6f63af3ee73f14d30aae2691a Mon Sep 17 00:00:00 2001 From: 1795771535y-cell <1795771535y@gmail.com> Date: Thu, 18 Jun 2026 19:58:51 +0800 Subject: [PATCH] Fix FTPDownloadHandler connection leak The FTPDownloadHandler.download_request() method creates FTPClient instances but never closes them, leading to resource leaks. Additionally, the ReceivedDataProtocol instance is not closed in the error path. This fix: 1. Closes the FTP client connection after successful file retrieval 2. Closes both the protocol and client connection in the error path 3. Uses client.transport.loseConnection() to properly close the connection Fixes #7602 Co-Authored-By: Claude --- scrapy/core/downloader/handlers/ftp.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/scrapy/core/downloader/handlers/ftp.py b/scrapy/core/downloader/handlers/ftp.py index 6258067c1..e23ad5d00 100644 --- a/scrapy/core/downloader/handlers/ftp.py +++ b/scrapy/core/downloader/handlers/ftp.py @@ -114,12 +114,17 @@ class FTPDownloadHandler(BaseDownloadHandler): await maybe_deferred_to_future(client.retrieveFile(filepath, protocol)) except CommandFailed as e: message = str(e) + # Close protocol and client on error to prevent resource leaks + protocol.close() + client.transport.loseConnection() if m := _CODE_RE.search(message): ftpcode = m.group() httpcode = self.CODE_MAPPING.get(ftpcode, self.CODE_MAPPING["default"]) return Response(url=request.url, status=httpcode, body=message.encode()) raise protocol.close() + # Close the FTP client connection to prevent resource leaks + 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)