mirror of
https://github.com/tahoe-lafs/tahoe-lafs.git
synced 2024-12-29 17:28:53 +00:00
SFTP: write an error message to standard error for unrecognized shell commands. Change the existing message for shell sessions to be written to standard error, and refactor some duplicated code. Also change the lines of the error messages to end in CRLF, and take into account Kevan's review comments. fixes #1442, #1446
This commit is contained in:
parent
b21a4f6b3f
commit
a2699ea6f6
@ -1868,10 +1868,7 @@ class ShellSession(PrefixingLogMixin):
|
|||||||
if hasattr(protocol, 'transport') and protocol.transport is None:
|
if hasattr(protocol, 'transport') and protocol.transport is None:
|
||||||
protocol.transport = FakeTransport() # work around Twisted bug
|
protocol.transport = FakeTransport() # work around Twisted bug
|
||||||
|
|
||||||
d = defer.succeed(None)
|
return self._unsupported(protocol)
|
||||||
d.addCallback(lambda ign: protocol.write("This server supports only SFTP, not shell sessions.\n"))
|
|
||||||
d.addCallback(lambda ign: protocol.processEnded(Reason(ProcessTerminated(exitCode=1))))
|
|
||||||
return d
|
|
||||||
|
|
||||||
def execCommand(self, protocol, cmd):
|
def execCommand(self, protocol, cmd):
|
||||||
self.log(".execCommand(%r, %r)" % (protocol, cmd), level=OPERATIONAL)
|
self.log(".execCommand(%r, %r)" % (protocol, cmd), level=OPERATIONAL)
|
||||||
@ -1881,10 +1878,18 @@ class ShellSession(PrefixingLogMixin):
|
|||||||
d = defer.succeed(None)
|
d = defer.succeed(None)
|
||||||
if cmd == "df -P -k /":
|
if cmd == "df -P -k /":
|
||||||
d.addCallback(lambda ign: protocol.write(
|
d.addCallback(lambda ign: protocol.write(
|
||||||
"Filesystem 1024-blocks Used Available Capacity Mounted on\n"
|
"Filesystem 1024-blocks Used Available Capacity Mounted on\r\n"
|
||||||
"tahoe 628318530 314159265 314159265 50% /\n"))
|
"tahoe 628318530 314159265 314159265 50% /\r\n"))
|
||||||
d.addCallback(lambda ign: protocol.processEnded(Reason(ProcessDone(None))))
|
d.addCallback(lambda ign: protocol.processEnded(Reason(ProcessDone(None))))
|
||||||
else:
|
else:
|
||||||
|
d.addCallback(lambda ign: self._unsupported(protocol))
|
||||||
|
return d
|
||||||
|
|
||||||
|
def _unsupported(self, protocol):
|
||||||
|
d = defer.succeed(None)
|
||||||
|
d.addCallback(lambda ign: protocol.errReceived(
|
||||||
|
"This server supports only the SFTP protocol. It does not support SCP,\r\n"
|
||||||
|
"interactive shell sessions, or commands other than one needed by sshfs.\r\n"))
|
||||||
d.addCallback(lambda ign: protocol.processEnded(Reason(ProcessTerminated(exitCode=1))))
|
d.addCallback(lambda ign: protocol.processEnded(Reason(ProcessTerminated(exitCode=1))))
|
||||||
return d
|
return d
|
||||||
|
|
||||||
|
@ -1327,49 +1327,69 @@ class Handler(GridTestMixin, ShouldFailMixin, ReallyEqualMixin, unittest.TestCas
|
|||||||
return d
|
return d
|
||||||
|
|
||||||
def test_execCommand_and_openShell(self):
|
def test_execCommand_and_openShell(self):
|
||||||
class FakeProtocol:
|
class MockProtocol:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.output = ""
|
self.output = ""
|
||||||
|
self.error = ""
|
||||||
self.reason = None
|
self.reason = None
|
||||||
|
|
||||||
def write(self, data):
|
def write(self, data):
|
||||||
|
return self.outReceived(data)
|
||||||
|
|
||||||
|
def outReceived(self, data):
|
||||||
self.output += data
|
self.output += data
|
||||||
return defer.succeed(None)
|
return defer.succeed(None)
|
||||||
|
|
||||||
|
def errReceived(self, data):
|
||||||
|
self.error += data
|
||||||
|
return defer.succeed(None)
|
||||||
|
|
||||||
def processEnded(self, reason):
|
def processEnded(self, reason):
|
||||||
self.reason = reason
|
self.reason = reason
|
||||||
return defer.succeed(None)
|
return defer.succeed(None)
|
||||||
|
|
||||||
|
def _lines_end_in_crlf(s):
|
||||||
|
return s.replace('\r\n', '').find('\n') == -1 and s.endswith('\r\n')
|
||||||
|
|
||||||
d = self._set_up("execCommand_and_openShell")
|
d = self._set_up("execCommand_and_openShell")
|
||||||
|
|
||||||
d.addCallback(lambda ign: conch_interfaces.ISession(self.handler))
|
d.addCallback(lambda ign: conch_interfaces.ISession(self.handler))
|
||||||
def _exec_df(session):
|
def _exec_df(session):
|
||||||
protocol = FakeProtocol()
|
protocol = MockProtocol()
|
||||||
d2 = session.execCommand(protocol, "df -P -k /")
|
d2 = session.execCommand(protocol, "df -P -k /")
|
||||||
d2.addCallback(lambda ign: self.failUnlessIn("1024-blocks", protocol.output))
|
d2.addCallback(lambda ign: self.failUnlessIn("1024-blocks", protocol.output))
|
||||||
|
d2.addCallback(lambda ign: self.failUnless(_lines_end_in_crlf(protocol.output), protocol.output))
|
||||||
|
d2.addCallback(lambda ign: self.failUnlessEqual(protocol.error, ""))
|
||||||
d2.addCallback(lambda ign: self.failUnless(isinstance(protocol.reason.value, ProcessDone)))
|
d2.addCallback(lambda ign: self.failUnless(isinstance(protocol.reason.value, ProcessDone)))
|
||||||
d2.addCallback(lambda ign: session.eofReceived())
|
d2.addCallback(lambda ign: session.eofReceived())
|
||||||
d2.addCallback(lambda ign: session.closed())
|
d2.addCallback(lambda ign: session.closed())
|
||||||
return d2
|
return d2
|
||||||
d.addCallback(_exec_df)
|
d.addCallback(_exec_df)
|
||||||
|
|
||||||
d.addCallback(lambda ign: conch_interfaces.ISession(self.handler))
|
def _check_unsupported(protocol):
|
||||||
def _exec_error(session):
|
d2 = defer.succeed(None)
|
||||||
protocol = FakeProtocol()
|
d2.addCallback(lambda ign: self.failUnlessEqual(protocol.output, ""))
|
||||||
d2 = session.execCommand(protocol, "error")
|
d2.addCallback(lambda ign: self.failUnlessIn("only the SFTP protocol", protocol.error))
|
||||||
d2.addCallback(lambda ign: session.windowChanged(None))
|
d2.addCallback(lambda ign: self.failUnless(_lines_end_in_crlf(protocol.error), protocol.error))
|
||||||
d2.addCallback(lambda ign: self.failUnlessEqual("", protocol.output))
|
|
||||||
d2.addCallback(lambda ign: self.failUnless(isinstance(protocol.reason.value, ProcessTerminated)))
|
d2.addCallback(lambda ign: self.failUnless(isinstance(protocol.reason.value, ProcessTerminated)))
|
||||||
d2.addCallback(lambda ign: self.failUnlessEqual(protocol.reason.value.exitCode, 1))
|
d2.addCallback(lambda ign: self.failUnlessEqual(protocol.reason.value.exitCode, 1))
|
||||||
|
return d2
|
||||||
|
|
||||||
|
d.addCallback(lambda ign: conch_interfaces.ISession(self.handler))
|
||||||
|
def _exec_error(session):
|
||||||
|
protocol = MockProtocol()
|
||||||
|
d2 = session.execCommand(protocol, "error")
|
||||||
|
d2.addCallback(lambda ign: session.windowChanged(None))
|
||||||
|
d2.addCallback(lambda ign: _check_unsupported(protocol))
|
||||||
d2.addCallback(lambda ign: session.closed())
|
d2.addCallback(lambda ign: session.closed())
|
||||||
return d2
|
return d2
|
||||||
d.addCallback(_exec_error)
|
d.addCallback(_exec_error)
|
||||||
|
|
||||||
d.addCallback(lambda ign: conch_interfaces.ISession(self.handler))
|
d.addCallback(lambda ign: conch_interfaces.ISession(self.handler))
|
||||||
def _openShell(session):
|
def _openShell(session):
|
||||||
protocol = FakeProtocol()
|
protocol = MockProtocol()
|
||||||
d2 = session.openShell(protocol)
|
d2 = session.openShell(protocol)
|
||||||
d2.addCallback(lambda ign: self.failUnlessIn("only SFTP", protocol.output))
|
d2.addCallback(lambda ign: _check_unsupported(protocol))
|
||||||
d2.addCallback(lambda ign: self.failUnless(isinstance(protocol.reason.value, ProcessTerminated)))
|
|
||||||
d2.addCallback(lambda ign: self.failUnlessEqual(protocol.reason.value.exitCode, 1))
|
|
||||||
d2.addCallback(lambda ign: session.closed())
|
d2.addCallback(lambda ign: session.closed())
|
||||||
return d2
|
return d2
|
||||||
d.addCallback(_openShell)
|
d.addCallback(_openShell)
|
||||||
|
Loading…
Reference in New Issue
Block a user