gpt4 book ai didi

python - 限制 Twisted FTP 服务器中的文件大小

转载 作者:太空宇宙 更新时间:2023-11-04 05:11:24 25 4
gpt4 key购买 nike

我正在尝试使用限制上传文件大小的 twisted 实现 FTP 服务器。理想情况下,这会在传输开始之前发生,但如果它在传输过程中因太大而正常退出,这并不是真正的问题。

我从最基本的 ftpserver.py 开始,慢慢地从 ftp.py 中引入更多的底层类以深入到内部。

下面的当前代码,请原谅我使用的“hack-and-slash”风格,直到我让它工作。

#!/usr/bin/python
import os

from twisted.protocols.ftp import FTPFactory, FTPShell, FTPAnonymousShell, IFTPShell
from twisted.cred.portal import Portal
from twisted.cred.checkers import AllowAnonymousAccess
from twisted.internet import reactor, defer
from twisted.python import filepath, failure

class FileConsumer1(object):
def __init__(self, fObj):
self.fObj = fObj

def registerProducer(self, producer, streaming):
self.producer = producer
assert streaming

def unregisterProducer(self):
self.producer = None
self.fObj.close()

def write(self, bytes):
size = os.fstat(self.fObj.fileno()).st_size + len(bytes)
if size > 10:
raise Exception("File too large") # WHAT GOES HERE?
self.fObj.write(bytes)

class FileWriter1(object):
def __init__(self, fObj):
self.fObj = fObj
self._receive = False

def receive(self):
assert not self._receive, "Can only call IWriteFile.receive *once* per instance"
self._receive = True
return defer.succeed(FileConsumer1(self.fObj))

def close(self):
return defer.succeed(None)

class FTPShell1(FTPShell):
def openForWriting(self, path):

p = self._path(path)
if p.isdir():
return defer.fail(IsADirectoryError(path))
try:
fObj = p.open('w')
except (IOError, OSError), e:
return errnoToFailure(e.errno, path)
except:
return defer.fail()
return defer.succeed(FileWriter1(fObj))

class FTPRealm1(object):
def __init__(self, root):
self.path = filepath.FilePath(root)

def requestAvatar(self, avatarId, mind, *interfaces):
avatar = FTPShell1(self.path)
return (IFTPShell, avatar, getattr(avatar, 'logout', lambda: None))

p = Portal(FTPRealm1('./'), [ AllowAnonymousAccess() ])

f = FTPFactory(p)

reactor.listenTCP(4021, f)
reactor.run()

很明显检查 size > 10 会更大,但是此时 a 应该如何指示存在问题?就目前而言,twisted 捕获了该异常,但它不是很优雅。据我对 ftp.py 的检查可以看出,没有什么明显的我可以返回这里。我可以通过某种方式传递延迟吗?我应该如何优雅地关闭传输?

谢谢,

修改后的版本

#!/usr/bin/python
import os

from zope.interface import Interface, implements

from twisted.protocols.ftp import FTPFactory, FTPShell, FTPAnonymousShell, IFTPShell, IWriteFile , BaseFTPRealm, FTPCmdError, EXCEEDED_STORAGE_ALLOC
from twisted.cred.portal import Portal
from twisted.cred.checkers import AllowAnonymousAccess
from twisted.internet import reactor, defer, interfaces
from twisted.python import filepath

class ExceededStorageAllocError(FTPCmdError):
errorCode = EXCEEDED_STORAGE_ALLOC

class FileConsumer(object):
implements(interfaces.IConsumer)
def __init__(self):
self.data = ""
self.error = None

def registerProducer(self, producer, streaming):
self.producer = producer
assert streaming

def unregisterProducer(self):
if self.producer:
self.producer.stopProducing()
self.producer = None

def write(self, bytes):
self.data += bytes
if len(self.data) > 10:
self.unregisterProducer()
self.error = ExceededStorageAllocError()

class FileWriter(object):
implements(IWriteFile)
def __init__(self, path):
self.path = path

def receive(self):
self.consumer = FileConsumer()
return defer.succeed(self.consumer)

def close(self):
if self.consumer.error:
return defer.fail(self.consumer.error)
try:
f = self.path.open('w')
except (IOError, OSError), e:
return errnoToFailure(e.errno, path)
f.write(self.consumer.data)
return defer.succeed(None)

class FTPShell1(FTPShell):
makeDirectory = FTPAnonymousShell.makeDirectory
removeDirectory = FTPAnonymousShell.removeDirectory
def openForWriting(self, path):
p = self._path(path)
if p.isdir():
return defer.fail(IsADirectoryError(path))
return defer.succeed(FileWriter(p))

class FTPRealm1(BaseFTPRealm):
def __init__(self, root):
self.root = root

def requestAvatar(self, avatarId, mind, *interfaces):
avatar = FTPShell1(filepath.FilePath(self.root))
return (IFTPShell, avatar, getattr(avatar, 'logout', lambda: None))

p = Portal(FTPRealm1('./'), [ AllowAnonymousAccess() ])

f = FTPFactory(p)

reactor.listenTCP(4021, f)
reactor.run()

如果文件太长,它将在 FileConsumer() 中累积接收到的数据然后中止。然后 FileWriter() 的 close() 方法要么报告该错误,要么将整个缓冲区写入文件。

我遇到的唯一真正的问题是运行时,异常显示在服务器上:

Unexpected error received during transfer:
Traceback (most recent call last):
Failure: __main__.ExceededStorageAllocError:

最佳答案

作为快速免责声明,我对 Twisted 的生产者/消费者模型非常不满意,所以这可能行不通。一如既往,如果事情爆发,我概不负责;)

您似乎走在正确的道路上,因此请为自己鼓掌。我认为如果您在文件太大时调用 unregisterProducer,该文件应该停止使用。您可能还需要调用 self.producer.stopProducing(),但不要引用我的话。

def unregisterProducer(self):
self.producer.stopProducing()
self.fObj.close()

def write(self, bytes):
size = os.fstat(self.fObj.fileno()).st_size + len(bytes)
if size > 10:
self.unregisterConsumer()
# log statements would go here
# do some clean up too
self.fObj.write(bytes)

如果我的心理代码 Python 解释器是正确的,这应该只是停止使用文件。至于您应该返回给客户端的内容,您必须阅读有关 FTP 的 RFC 才能弄明白。

附言

尽管看起来很乏味,但请使用 @implementor 装饰器。大多数时候你会没事的,但可能会出现意想不到的回溯。

关于python - 限制 Twisted FTP 服务器中的文件大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42910061/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com