[Zope3-checkins] SVN: Zope3/trunk/src/zope/app/ Fix the FTP server.
The twisted interface changed and these fixes reflect
Michael Kerrin
michael.kerrin at openapp.biz
Mon Oct 17 13:04:18 EDT 2005
Log message for revision 39487:
Fix the FTP server. The twisted interface changed and these fixes reflect
that. The zope.app.ftp component received a new method `readable' that works
in a similar mannor to the writable method.
Changed:
U Zope3/trunk/src/zope/app/ftp/__init__.py
U Zope3/trunk/src/zope/app/ftp/configure.zcml
U Zope3/trunk/src/zope/app/ftp/tests/test_ftpview.py
U Zope3/trunk/src/zope/app/twisted/ftp/ftp.py
U Zope3/trunk/src/zope/app/twisted/ftp/test/test_zope_ftp.py
U Zope3/trunk/src/zope/app/twisted/ftp/tests/demofs.py
U Zope3/trunk/src/zope/app/twisted/ftp/utils.py
U Zope3/trunk/src/zope/app/twisted/interfaces.py
-=-
Modified: Zope3/trunk/src/zope/app/ftp/__init__.py
===================================================================
--- Zope3/trunk/src/zope/app/ftp/__init__.py 2005-10-17 15:57:08 UTC (rev 39486)
+++ Zope3/trunk/src/zope/app/ftp/__init__.py 2005-10-17 17:04:17 UTC (rev 39487)
@@ -22,6 +22,7 @@
from zope.component import queryAdapter
from zope.publisher.interfaces.ftp import IFTPPublisher
from zope.security.proxy import removeSecurityProxy
+from zope.security.checker import canAccess
from zope.app.filerepresentation.interfaces import IReadFile, IWriteFile
from zope.app.filerepresentation.interfaces import IReadDirectory
@@ -75,7 +76,6 @@
if filter(name)]
def _lsinfo(self, name, file):
-
info = {'name': name,
'mtime': self._mtime(file),
}
@@ -222,8 +222,18 @@
def writable(self, name):
if name in self._dir:
f = IWriteFile(self._dir[name], None)
- return hasattr(f, 'write')
+ if f is not None:
+ return canAccess(f, 'write')
+ return False
d = IWriteDirectory(self.context, None)
- return hasattr(d, '__setitem__')
+ return canAccess(d, '__setitem__')
-
+ def readable(self, name):
+ if name in self._dir:
+ f = IReadFile(self._dir[name], None)
+ if f is not None:
+ return canAccess(f, 'read')
+ d = IReadDirectory(self._dir[name], name)
+ if d is not None:
+ return canAccess(d, 'get')
+ return False
Modified: Zope3/trunk/src/zope/app/ftp/configure.zcml
===================================================================
--- Zope3/trunk/src/zope/app/ftp/configure.zcml 2005-10-17 15:57:08 UTC (rev 39486)
+++ Zope3/trunk/src/zope/app/ftp/configure.zcml 2005-10-17 17:04:17 UTC (rev 39487)
@@ -148,4 +148,14 @@
"zope.app.publisher.interfaces.ftp.IFTPDirectoryPublisher"
/>
+ <view
+ for="zope.app.container.interfaces.IReadContainer"
+ name="readable"
+ type="zope.publisher.interfaces.ftp.IFTPRequest"
+ factory=".FTPView"
+ permission="zope.Public"
+ allowed_interface=
+ "zope.app.publisher.interfaces.ftp.IFTPDirectoryPublisher"
+ />
+
</configure>
Modified: Zope3/trunk/src/zope/app/ftp/tests/test_ftpview.py
===================================================================
--- Zope3/trunk/src/zope/app/ftp/tests/test_ftpview.py 2005-10-17 15:57:08 UTC (rev 39486)
+++ Zope3/trunk/src/zope/app/ftp/tests/test_ftpview.py 2005-10-17 17:04:17 UTC (rev 39487)
@@ -20,6 +20,7 @@
from unittest import TestCase, TestSuite, main, makeSuite
from zope.interface import implements
+from zope.security.checker import defineChecker, NamesChecker
from zope.app.testing import ztapi
from zope.app.filerepresentation.interfaces import IReadFile, IWriteFile
@@ -112,12 +113,21 @@
def setUp(self):
super(Test, self).setUp()
+
+ ## Make objects
+ filechecker = NamesChecker(['write', 'read'])
+ dirchecker = NamesChecker(['__setitem__', 'get'])
+ defineChecker(File, filechecker)
+ defineChecker(Directory, dirchecker)
+
root = Directory()
root['test'] = Directory()
root['test2'] = Directory()
root['f'] = File('contents of\nf')
root['g'] = File('contents of\ng')
self.__view = FTPView(root, None)
+
+ ## declare adapters
ztapi.provideAdapter(IContainer, IContainerItemRenamer,
ContainerItemRenamer)
@@ -258,6 +268,11 @@
self.assert_(self.__view.writable('notthere'))
self.assert_(not self.__view.writable('test'))
+ def test_readable(self):
+ self.assert_(self.__view.readable('f'))
+ self.assert_(not self.__view.readable('notthere'))
+ self.assert_(self.__view.readable('test'))
+
def test_suite():
return TestSuite((
makeSuite(Test),
Modified: Zope3/trunk/src/zope/app/twisted/ftp/ftp.py
===================================================================
--- Zope3/trunk/src/zope/app/twisted/ftp/ftp.py 2005-10-17 15:57:08 UTC (rev 39486)
+++ Zope3/trunk/src/zope/app/twisted/ftp/ftp.py 2005-10-17 17:04:17 UTC (rev 39487)
@@ -50,6 +50,50 @@
self.buffer.append(bytes)
+class ReadFileObj(object):
+ implements(ftp.IReadFile)
+
+ def __init__(self, fs, path):
+ self.fs_access = fs
+ self.path = path
+
+ def send(self, consumer):
+ def failed(failure):
+ consumer.unregisterProducer()
+
+ def success(passthrough):
+ consumer.unregisterProducer()
+
+ d = threads.deferToThread(self.fs_access.readfile, self.path, consumer)
+ d.addCallback(success)
+ d.addErrback(failed)
+
+ return d
+
+
+class WriteFileObj(object):
+ implements(ftp.IWriteFile)
+
+ def __init__(self, fs, path):
+ self.fs_access = fs
+ self.path = path
+
+ def receive(self):
+ def accessok(result, fs):
+ if not result:
+ raise ftp.PermissionDeniedError(self.path)
+ return ConsumerObject(fs, self.path)
+
+ def failure(failure):
+ raise ftp.PermissionDeniedError(self.path)
+
+ d = threads.deferToThread(self.fs_access.writable, self.path)
+ d.addCallback(accessok, self.fs_access)
+ d.addErrback(failure)
+
+ return d
+
+
class ZopeFTPShell(object):
"""An abstraction of the shell commands used by the FTP protocol
for a given user account
@@ -128,7 +172,6 @@
def _stat(self, path, keys):
if self.fs_access.type(path) == 'd':
- import pdb; pdb.set_trace()
raise ftp.WrongFiletype()
result = self._gotlisting(self.fs_access.lsinfo(path), keys)
return result[1]
@@ -201,37 +244,36 @@
ret |= 0040000
return ret
- def send(self, path, consumer):
- def finished(result, consumer):
- consumer.transport.loseConnection()
+ def openForReading(self, path):
+ p = self._path(path)
- def failed(failure, consumer):
- consumer.transport.loseConnection()
- if failure.type is NotFound:
- raise ftp.FileNotFoundError(self._path(path))
- ## Unauthorized error - is there any other errors I should
- ## be catching.
- raise ftp.PermissionDeniedError(self._path(path))
+ def succeed(result):
+ if not result:
+ raise ftp.PermissionDeniedError(p)
+ return ReadFileObj(self.fs_access, p)
- p = self._path(path)
- d = threads.deferToThread(self.fs_access.readfile, p, consumer)
- d.addCallback(finished, consumer)
- d.addErrback(failed, consumer)
+ def failed(failure):
+ raise ftp.PermissionDeniedError(p)
+
+ d = threads.deferToThread(self.fs_access.readable, p)
+ d.addCallback(succeed)
+ d.addErrback(failed)
+
return d
- def receive(self, path):
- def accessok(result, fs):
- if not result:
- raise ftp.PermissionDeniedError(self._path(path))
- return ConsumerObject(fs, p)
+ def openForWriting(self, path):
+ p = self._path(path)
- def failure(result):
- ## XXX - should be a better exception
- raise ftp.PermissionDeniedError(path)
+ def succeed(result):
+ if result:
+ return WriteFileObj(self.fs_access, p)
+ raise ftp.PermissionDeniedError(p)
- p = self._path(path)
+ def failed(failure):
+ raise ftp.PermissionDeniedError(p)
+
d = threads.deferToThread(self.fs_access.writable, p)
- d.addCallback(accessok, self.fs_access)
- d.addErrback(failure)
+ d.addCallback(succeed)
+ d.addErrback(failed)
return d
Modified: Zope3/trunk/src/zope/app/twisted/ftp/test/test_zope_ftp.py
===================================================================
--- Zope3/trunk/src/zope/app/twisted/ftp/test/test_zope_ftp.py 2005-10-17 15:57:08 UTC (rev 39486)
+++ Zope3/trunk/src/zope/app/twisted/ftp/test/test_zope_ftp.py 2005-10-17 17:04:17 UTC (rev 39487)
@@ -279,8 +279,14 @@
filenames.sort()
self.assertEqual([self.filename], filenames)
+ def testRETR_wo_Permission(self):
+ self._michaelLogin()
+
downloader = self._makeDataConnection()
d = self.client.queueStringCommand('RETR %s' % self.filename)
failureResponseLines = self._waitForCommandFailure(d)
- self.failUnless(failureResponseLines[-1].startswith('426'),
- "Response didn't start with 426 i.e. data connection closed error")
+ self.failUnless(failureResponseLines[-1].startswith('550'),
+ "Response didn't start with 550: %r" %
+ failureResponseLines[-1])
+ if downloader.transport.connected:
+ downloader.transport.loseConnection()
Modified: Zope3/trunk/src/zope/app/twisted/ftp/tests/demofs.py
===================================================================
--- Zope3/trunk/src/zope/app/twisted/ftp/tests/demofs.py 2005-10-17 15:57:08 UTC (rev 39486)
+++ Zope3/trunk/src/zope/app/twisted/ftp/tests/demofs.py 2005-10-17 17:04:17 UTC (rev 39487)
@@ -294,6 +294,19 @@
f = d[name]
return f.type == 'f' and f.accessable(self.user, write)
+ def readable(self, path):
+ path, name = posixpath.split(path)
+ try:
+ d = self.getdir(path)
+ except OSError:
+ return False
+
+ if name not in d:
+ return False
+
+ f = d[name]
+ return f.type == 'f' and f.accessable(self.user, read)
+
## class DemoFileSystemAccess(object):
## __doc__ = IFileSystemAccess.__doc__
Modified: Zope3/trunk/src/zope/app/twisted/ftp/utils.py
===================================================================
--- Zope3/trunk/src/zope/app/twisted/ftp/utils.py 2005-10-17 15:57:08 UTC (rev 39486)
+++ Zope3/trunk/src/zope/app/twisted/ftp/utils.py 2005-10-17 17:04:17 UTC (rev 39487)
@@ -139,6 +139,9 @@
'See IWriteFileSystem'
return self._execute(path, 'writable')
+ def readable(self, path):
+ return self._execute(path, 'readable')
+
def _execute(self, path, command, split=True, **kw):
env = {}
env.update(kw)
Modified: Zope3/trunk/src/zope/app/twisted/interfaces.py
===================================================================
--- Zope3/trunk/src/zope/app/twisted/interfaces.py 2005-10-17 15:57:08 UTC (rev 39486)
+++ Zope3/trunk/src/zope/app/twisted/interfaces.py 2005-10-17 17:04:17 UTC (rev 39487)
@@ -255,3 +255,9 @@
exist but its directory is writable.
"""
+
+ def readable(path):
+ """Return boolean indicating whether a file at path is readable.
+
+ Return False if the file doesn't exist.
+ """
More information about the Zope3-Checkins
mailing list