This is an automated email from the ASF dual-hosted git repository. twolf pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/mina-sshd.git
The following commit(s) were added to refs/heads/master by this push: new dc229b9fe [SSHD-1257] ChannelSession: don't flush out stream if already closed dc229b9fe is described below commit dc229b9fe9c04127bb9086a4393633e57cbdcdef Author: Vincent Latombe <vinc...@latombe.net> AuthorDate: Thu Mar 31 15:40:15 2022 +0200 [SSHD-1257] ChannelSession: don't flush out stream if already closed Since OutputStream.close() is a no-op when the stream is already closed and does flush if not, use close() instead of flush(). This use in ChannelSession is the last use of this OutputStream. It may get closed again when the ChannelSession itself closes, but that is then just a no-op. --- .../apache/sshd/server/channel/ChannelSession.java | 2 +- .../sshd/server/channel/ChannelSessionTest.java | 54 ++++++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelSession.java b/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelSession.java index 84b8b72e1..2bba1d46e 100644 --- a/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelSession.java +++ b/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelSession.java @@ -908,7 +908,7 @@ public class ChannelSession extends AbstractServerChannel { if (!isClosing()) { if (out != null) { - out.flush(); + out.close(); } sendEof(); sendExitStatus(exitValue); diff --git a/sshd-core/src/test/java/org/apache/sshd/server/channel/ChannelSessionTest.java b/sshd-core/src/test/java/org/apache/sshd/server/channel/ChannelSessionTest.java index 803b6c124..af8bf9540 100644 --- a/sshd-core/src/test/java/org/apache/sshd/server/channel/ChannelSessionTest.java +++ b/sshd-core/src/test/java/org/apache/sshd/server/channel/ChannelSessionTest.java @@ -58,6 +58,60 @@ public class ChannelSessionTest extends BaseTestSupport { super(); } + /** + * Testing a command closing output stream when it completes + */ + @Test // see SSHD-1257 + public void closeOutputStream() throws Exception { + try (SshServer server = setupTestServer(); + SshClient client = setupTestClient()) { + + server.setShellFactory(session -> new CommandExecutionHelper(null) { + @Override + protected boolean handleCommandLine(String command) throws Exception { + OutputStream out = getOutputStream(); + out.write((command + "\n").getBytes(StandardCharsets.UTF_8)); + boolean more = !"exit".equals(command); + if (!more) { + out.close(); + } + return more; + } + }); + server.start(); + client.start(); + + try (ClientSession session = client.connect(getCurrentTestName(), TEST_LOCALHOST, server.getPort()) + .verify(CONNECT_TIMEOUT).getSession()) { + session.addPasswordIdentity(getCurrentTestName()); + session.auth().verify(AUTH_TIMEOUT); + + try (ClientChannel channel = session.createChannel(Channel.CHANNEL_SHELL)) { + channel.open().verify(OPEN_TIMEOUT); + + OutputStream invertedIn = channel.getInvertedIn(); + String cmdSent = "echo foo\nexit\n"; + invertedIn.write(cmdSent.getBytes()); + invertedIn.flush(); + + long waitStart = System.currentTimeMillis(); + Collection<ClientChannelEvent> result + = channel.waitFor(EnumSet.of(ClientChannelEvent.CLOSED), TimeUnit.SECONDS.toMillis(11L)); + long waitEnd = System.currentTimeMillis(); + assertTrue("Wrong channel state after " + (waitEnd - waitStart) + " ms.: " + result, + result.containsAll(EnumSet.of(ClientChannelEvent.CLOSED))); + + byte[] b = new byte[1024]; + InputStream invertedOut = channel.getInvertedOut(); + int l = invertedOut.read(b); + String cmdReceived = (l > 0) ? new String(b, 0, l) : ""; + + assertEquals("Mismatched echoed command", cmdSent, cmdReceived); + } + } + } + } + @Test public void testNoFlush() throws Exception { try (SshServer server = setupTestServer();