Repository: mina-sshd Updated Branches: refs/heads/master 014bf86c5 -> 1cd204b7a
[SSHD-787] Provide fine-grained control over SCP stream paths resolution Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/1cd204b7 Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/1cd204b7 Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/1cd204b7 Branch: refs/heads/master Commit: 1cd204b7ad221d74211d67b3a4659b6210a6fa56 Parents: 014bf86 Author: Lyor Goldstein <[email protected]> Authored: Fri Dec 15 19:05:27 2017 +0200 Committer: Lyor Goldstein <[email protected]> Committed: Mon Dec 18 19:57:33 2017 +0200 ---------------------------------------------------------------------- .../sshd/client/ClientFactoryManager.java | 2 + .../java/org/apache/sshd/client/SshClient.java | 12 +++++ .../sshd/client/scp/DefaultScpClient.java | 16 +++++-- .../sshd/client/scp/ScpClientCreator.java | 29 +++++++++--- .../client/session/AbstractClientSession.java | 16 ++++++- .../sshd/client/subsystem/sftp/SftpCommand.java | 2 +- .../org/apache/sshd/common/scp/ScpHelper.java | 18 +++---- .../common/scp/ScpStreamResolverFactory.java | 32 +++++++++++++ .../scp/ScpStreamResolverFactoryHolder.java | 29 ++++++++++++ .../DefaultScpStreamResolverFactory.java | 50 ++++++++++++++++++++ .../org/apache/sshd/server/scp/ScpCommand.java | 10 ++-- .../sshd/server/scp/ScpCommandFactory.java | 27 ++++++++++- .../org/apache/sshd/client/scp/ScpTest.java | 11 +++-- 13 files changed, 224 insertions(+), 30 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/1cd204b7/sshd-core/src/main/java/org/apache/sshd/client/ClientFactoryManager.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/client/ClientFactoryManager.java b/sshd-core/src/main/java/org/apache/sshd/client/ClientFactoryManager.java index 31b2a22..e116651 100644 --- a/sshd-core/src/main/java/org/apache/sshd/client/ClientFactoryManager.java +++ b/sshd-core/src/main/java/org/apache/sshd/client/ClientFactoryManager.java @@ -24,6 +24,7 @@ import org.apache.sshd.client.session.ClientProxyConnectorHolder; import org.apache.sshd.common.FactoryManager; import org.apache.sshd.common.config.keys.FilePasswordProvider; import org.apache.sshd.common.scp.ScpFileOpenerHolder; +import org.apache.sshd.common.scp.ScpStreamResolverFactoryHolder; /** * The <code>ClientFactoryManager</code> enable the retrieval of additional @@ -34,6 +35,7 @@ import org.apache.sshd.common.scp.ScpFileOpenerHolder; public interface ClientFactoryManager extends FactoryManager, ScpFileOpenerHolder, + ScpStreamResolverFactoryHolder, ClientProxyConnectorHolder, ClientAuthenticationManager { http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/1cd204b7/sshd-core/src/main/java/org/apache/sshd/client/SshClient.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/client/SshClient.java b/sshd-core/src/main/java/org/apache/sshd/client/SshClient.java index 0e8979e..a23d098 100644 --- a/sshd-core/src/main/java/org/apache/sshd/client/SshClient.java +++ b/sshd-core/src/main/java/org/apache/sshd/client/SshClient.java @@ -115,6 +115,7 @@ import org.apache.sshd.common.keyprovider.KeyPairProvider; import org.apache.sshd.common.mac.BuiltinMacs; import org.apache.sshd.common.mac.Mac; import org.apache.sshd.common.scp.ScpFileOpener; +import org.apache.sshd.common.scp.ScpStreamResolverFactory; import org.apache.sshd.common.session.helpers.AbstractSession; import org.apache.sshd.common.util.GenericUtils; import org.apache.sshd.common.util.OsUtils; @@ -211,6 +212,7 @@ public class SshClient extends AbstractFactoryManager implements ClientFactoryMa private FilePasswordProvider filePasswordProvider; private PasswordIdentityProvider passwordIdentityProvider; private ScpFileOpener scpOpener; + private ScpStreamResolverFactory scpStreamFactory; private final List<Object> identities = new CopyOnWriteArrayList<>(); private final AuthenticationIdentitiesProvider identitiesProvider; @@ -248,6 +250,16 @@ public class SshClient extends AbstractFactoryManager implements ClientFactoryMa } @Override + public ScpStreamResolverFactory getScpStreamResolverFactory() { + return scpStreamFactory; + } + + @Override + public void setScpStreamResolverFactory(ScpStreamResolverFactory factory) { + scpStreamFactory = factory; + } + + @Override public ServerKeyVerifier getServerKeyVerifier() { return serverKeyVerifier; } http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/1cd204b7/sshd-core/src/main/java/org/apache/sshd/client/scp/DefaultScpClient.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/client/scp/DefaultScpClient.java b/sshd-core/src/main/java/org/apache/sshd/client/scp/DefaultScpClient.java index d69252c..ead4c52 100644 --- a/sshd-core/src/main/java/org/apache/sshd/client/scp/DefaultScpClient.java +++ b/sshd-core/src/main/java/org/apache/sshd/client/scp/DefaultScpClient.java @@ -47,9 +47,11 @@ import org.apache.sshd.common.file.util.MockPath; import org.apache.sshd.common.scp.ScpFileOpener; import org.apache.sshd.common.scp.ScpHelper; import org.apache.sshd.common.scp.ScpLocation; +import org.apache.sshd.common.scp.ScpStreamResolverFactory; import org.apache.sshd.common.scp.ScpTimestamp; import org.apache.sshd.common.scp.ScpTransferEventListener; import org.apache.sshd.common.scp.helpers.DefaultScpFileOpener; +import org.apache.sshd.common.scp.helpers.DefaultScpStreamResolverFactory; import org.apache.sshd.common.util.GenericUtils; import org.apache.sshd.common.util.ValidateUtils; import org.apache.sshd.common.util.io.NoCloseInputStream; @@ -64,12 +66,16 @@ public class DefaultScpClient extends AbstractScpClient { public static final String SCP_PORT_OPTION = "-P"; protected final ScpFileOpener opener; + protected final ScpStreamResolverFactory streamFactory; protected final ScpTransferEventListener listener; private final ClientSession clientSession; - public DefaultScpClient(ClientSession clientSession, ScpFileOpener fileOpener, ScpTransferEventListener eventListener) { + public DefaultScpClient( + ClientSession clientSession, ScpFileOpener fileOpener, + ScpStreamResolverFactory streamFactory, ScpTransferEventListener eventListener) { this.clientSession = Objects.requireNonNull(clientSession, "No client session"); this.opener = (fileOpener == null) ? DefaultScpFileOpener.INSTANCE : fileOpener; + this.streamFactory = (streamFactory == null) ? DefaultScpStreamResolverFactory.INSTANCE : streamFactory; this.listener = (eventListener == null) ? ScpTransferEventListener.EMPTY : eventListener; } @@ -86,7 +92,7 @@ public class DefaultScpClient extends AbstractScpClient { try (InputStream invOut = channel.getInvertedOut(); OutputStream invIn = channel.getInvertedIn()) { // NOTE: we use a mock file system since we expect no invocations for it - ScpHelper helper = new ScpHelper(session, invOut, invIn, new MockFileSystem(remote), opener, listener); + ScpHelper helper = new ScpHelper(session, invOut, invIn, new MockFileSystem(remote), opener, streamFactory, listener); helper.receiveFileStream(local, ScpHelper.DEFAULT_RECEIVE_BUFFER_SIZE); handleCommandExitStatus(cmd, channel); } finally { @@ -101,7 +107,7 @@ public class DefaultScpClient extends AbstractScpClient { ChannelExec channel = openCommandChannel(session, cmd); try (InputStream invOut = channel.getInvertedOut(); OutputStream invIn = channel.getInvertedIn()) { - ScpHelper helper = new ScpHelper(session, invOut, invIn, fs, opener, listener); + ScpHelper helper = new ScpHelper(session, invOut, invIn, fs, opener, streamFactory, listener); helper.receive(local, options.contains(Option.Recursive), options.contains(Option.TargetIsDirectory), @@ -126,7 +132,7 @@ public class DefaultScpClient extends AbstractScpClient { try (InputStream invOut = channel.getInvertedOut(); OutputStream invIn = channel.getInvertedIn()) { // NOTE: we use a mock file system since we expect no invocations for it - ScpHelper helper = new ScpHelper(session, invOut, invIn, new MockFileSystem(remote), opener, listener); + ScpHelper helper = new ScpHelper(session, invOut, invIn, new MockFileSystem(remote), opener, streamFactory, listener); Path mockPath = new MockPath(remote); helper.sendStream(new DefaultScpStreamResolver(name, mockPath, perms, time, size, local, cmd), options.contains(Option.PreserveAttributes), ScpHelper.DEFAULT_SEND_BUFFER_SIZE); @@ -154,7 +160,7 @@ public class DefaultScpClient extends AbstractScpClient { try (InputStream invOut = channel.getInvertedOut(); OutputStream invIn = channel.getInvertedIn()) { - ScpHelper helper = new ScpHelper(session, invOut, invIn, fs, opener, listener); + ScpHelper helper = new ScpHelper(session, invOut, invIn, fs, opener, streamFactory, listener); executor.execute(helper, local, options); } finally { try { http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/1cd204b7/sshd-core/src/main/java/org/apache/sshd/client/scp/ScpClientCreator.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/client/scp/ScpClientCreator.java b/sshd-core/src/main/java/org/apache/sshd/client/scp/ScpClientCreator.java index b3199b2..502e5aa 100644 --- a/sshd-core/src/main/java/org/apache/sshd/client/scp/ScpClientCreator.java +++ b/sshd-core/src/main/java/org/apache/sshd/client/scp/ScpClientCreator.java @@ -21,22 +21,26 @@ package org.apache.sshd.client.scp; import org.apache.sshd.common.scp.ScpFileOpener; import org.apache.sshd.common.scp.ScpFileOpenerHolder; +import org.apache.sshd.common.scp.ScpStreamResolverFactory; +import org.apache.sshd.common.scp.ScpStreamResolverFactoryHolder; import org.apache.sshd.common.scp.ScpTransferEventListener; /** * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> */ -public interface ScpClientCreator extends ScpFileOpenerHolder { +public interface ScpClientCreator extends ScpFileOpenerHolder, ScpStreamResolverFactoryHolder { /** * Create an SCP client from this session. * * @return An {@link ScpClient} instance. <B>Note:</B> uses the currently - * registered {@link ScpTransferEventListener} and {@link ScpFileOpener} if any + * registered {@link ScpTransferEventListener}, {@link ScpStreamResolverFactoryHolder} + * and {@link ScpFileOpener} if any * @see #setScpFileOpener(ScpFileOpener) + * @see #setScpStreamResolverFactory(ScpStreamResolverFactory) * @see #setScpTransferEventListener(ScpTransferEventListener) */ default ScpClient createScpClient() { - return createScpClient(getScpFileOpener(), getScpTransferEventListener()); + return createScpClient(getScpFileOpener(), getScpStreamResolverFactory(), getScpTransferEventListener()); } /** @@ -49,7 +53,7 @@ public interface ScpClientCreator extends ScpFileOpenerHolder { * @return An {@link ScpClient} instance */ default ScpClient createScpClient(ScpTransferEventListener listener) { - return createScpClient(getScpFileOpener(), listener); + return createScpClient(getScpFileOpener(), getScpStreamResolverFactory(), listener); } /** @@ -62,7 +66,18 @@ public interface ScpClientCreator extends ScpFileOpenerHolder { * @return An {@link ScpClient} instance */ default ScpClient createScpClient(ScpFileOpener opener) { - return createScpClient(opener, getScpTransferEventListener()); + return createScpClient(opener, getScpStreamResolverFactory(), getScpTransferEventListener()); + } + + /** + * Create an SCP client from this session. + * + * @param factory The {@link ScpStreamResolverFactory} used to create input/output stream + * for incoming/outgoing files + * @return An {@link ScpClient} instance + */ + default ScpClient createScpClient(ScpStreamResolverFactory factory) { + return createScpClient(getScpFileOpener(), factory, getScpTransferEventListener()); } /** @@ -72,13 +87,15 @@ public interface ScpClientCreator extends ScpFileOpenerHolder { * are read/written. If {@code null} then a default opener is used. * <B>Note:</B> this opener is used <U>instead</U> of any instance * set via {@link #setScpFileOpener(ScpFileOpener)} + * @param factory The {@link ScpStreamResolverFactory} to use in order to create + * incoming/outgoing streams for received/sent files * @param listener A {@link ScpTransferEventListener} that can be used * to receive information about the SCP operations - may be {@code null} * to indicate no more events are required. <B>Note:</B> this listener * is used <U>instead</U> of any listener set via {@link #setScpTransferEventListener(ScpTransferEventListener)} * @return An {@link ScpClient} instance */ - ScpClient createScpClient(ScpFileOpener opener, ScpTransferEventListener listener); + ScpClient createScpClient(ScpFileOpener opener, ScpStreamResolverFactory factory, ScpTransferEventListener listener); /** * @return The last {@link ScpTransferEventListener} set via http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/1cd204b7/sshd-core/src/main/java/org/apache/sshd/client/session/AbstractClientSession.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/client/session/AbstractClientSession.java b/sshd-core/src/main/java/org/apache/sshd/client/session/AbstractClientSession.java index b67310d..ee8c550 100644 --- a/sshd-core/src/main/java/org/apache/sshd/client/session/AbstractClientSession.java +++ b/sshd-core/src/main/java/org/apache/sshd/client/session/AbstractClientSession.java @@ -66,6 +66,7 @@ import org.apache.sshd.common.io.IoWriteFuture; import org.apache.sshd.common.kex.KexProposalOption; import org.apache.sshd.common.kex.KexState; import org.apache.sshd.common.scp.ScpFileOpener; +import org.apache.sshd.common.scp.ScpStreamResolverFactory; import org.apache.sshd.common.scp.ScpTransferEventListener; import org.apache.sshd.common.session.ConnectionService; import org.apache.sshd.common.session.Session; @@ -90,6 +91,7 @@ public abstract class AbstractClientSession extends AbstractSession implements C private List<NamedFactory<UserAuth>> userAuthFactories; private ScpTransferEventListener scpListener; private ScpFileOpener scpOpener; + private ScpStreamResolverFactory scpStreamFactory; private SocketAddress connectAddress; private ClientProxyConnector proxyConnector; @@ -317,6 +319,16 @@ public abstract class AbstractClientSession extends AbstractSession implements C } @Override + public ScpStreamResolverFactory getScpStreamResolverFactory() { + return resolveEffectiveProvider(ScpStreamResolverFactory.class, scpStreamFactory, getFactoryManager().getScpStreamResolverFactory()); + } + + @Override + public void setScpStreamResolverFactory(ScpStreamResolverFactory factory) { + scpStreamFactory = factory; + } + + @Override public ScpTransferEventListener getScpTransferEventListener() { return scpListener; } @@ -327,8 +339,8 @@ public abstract class AbstractClientSession extends AbstractSession implements C } @Override - public ScpClient createScpClient(ScpFileOpener opener, ScpTransferEventListener listener) { - return new DefaultScpClient(this, opener, listener); + public ScpClient createScpClient(ScpFileOpener opener, ScpStreamResolverFactory factory, ScpTransferEventListener listener) { + return new DefaultScpClient(this, opener, factory, listener); } @Override http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/1cd204b7/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpCommand.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpCommand.java b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpCommand.java index 4865431..3b8e88f 100644 --- a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpCommand.java +++ b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpCommand.java @@ -81,7 +81,7 @@ public class SftpCommand implements Channel { public SftpCommand(SftpClient client) { this.client = Objects.requireNonNull(client, "No client"); - Map<String, CommandExecutor> map = new TreeMap<>(); + Map<String, CommandExecutor> map = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); for (CommandExecutor e : Arrays.asList( new ExitCommandExecutor(), new PwdCommandExecutor(), http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/1cd204b7/sshd-core/src/main/java/org/apache/sshd/common/scp/ScpHelper.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/scp/ScpHelper.java b/sshd-core/src/main/java/org/apache/sshd/common/scp/ScpHelper.java index 9918e02..0e75e83 100644 --- a/sshd-core/src/main/java/org/apache/sshd/common/scp/ScpHelper.java +++ b/sshd-core/src/main/java/org/apache/sshd/common/scp/ScpHelper.java @@ -48,8 +48,7 @@ import org.apache.sshd.common.SshException; import org.apache.sshd.common.file.util.MockPath; import org.apache.sshd.common.scp.ScpTransferEventListener.FileOperation; import org.apache.sshd.common.scp.helpers.DefaultScpFileOpener; -import org.apache.sshd.common.scp.helpers.LocalFileScpSourceStreamResolver; -import org.apache.sshd.common.scp.helpers.LocalFileScpTargetStreamResolver; +import org.apache.sshd.common.scp.helpers.DefaultScpStreamResolverFactory; import org.apache.sshd.common.session.Session; import org.apache.sshd.common.session.SessionHolder; import org.apache.sshd.common.util.GenericUtils; @@ -104,17 +103,20 @@ public class ScpHelper extends AbstractLoggingBean implements SessionHolder<Sess protected final OutputStream out; protected final FileSystem fileSystem; protected final ScpFileOpener opener; + protected final ScpStreamResolverFactory streamFactory; protected final ScpTransferEventListener listener; private final Session sessionInstance; public ScpHelper(Session session, InputStream in, OutputStream out, - FileSystem fileSystem, ScpFileOpener opener, ScpTransferEventListener eventListener) { + FileSystem fileSystem, ScpFileOpener opener, + ScpStreamResolverFactory streamFactory, ScpTransferEventListener eventListener) { this.sessionInstance = Objects.requireNonNull(session, "No session"); this.in = Objects.requireNonNull(in, "No input stream"); this.out = Objects.requireNonNull(out, "No output stream"); this.fileSystem = fileSystem; this.opener = (opener == null) ? DefaultScpFileOpener.INSTANCE : opener; + this.streamFactory = (streamFactory == null) ? DefaultScpStreamResolverFactory.INSTANCE : streamFactory; this.listener = (eventListener == null) ? ScpTransferEventListener.EMPTY : eventListener; } @@ -129,7 +131,7 @@ public class ScpHelper extends AbstractLoggingBean implements SessionHolder<Sess throw new StreamCorruptedException("Cannot download a directory into a file stream: " + line); } - final Path path = new MockPath(line); + Path path = new MockPath(line); receiveStream(line, new ScpTargetStreamResolver() { @SuppressWarnings("synthetic-access") @Override @@ -147,8 +149,8 @@ public class ScpHelper extends AbstractLoggingBean implements SessionHolder<Sess return path; } - @Override @SuppressWarnings("synthetic-access") + @Override public void postProcessReceivedData(String name, boolean preserve, Set<PosixFilePermission> perms, ScpTimestamp time) throws IOException { if (log.isDebugEnabled()) { log.debug("postProcessReceivedData({}) name={}, perms={}, preserve={} time={}", @@ -164,7 +166,7 @@ public class ScpHelper extends AbstractLoggingBean implements SessionHolder<Sess }); } - public void receive(Path local, boolean recursive, boolean shouldBeDir, boolean preserve, final int bufferSize) throws IOException { + public void receive(Path local, boolean recursive, boolean shouldBeDir, boolean preserve, int bufferSize) throws IOException { Path path = Objects.requireNonNull(local, "No local path").normalize().toAbsolutePath(); if (shouldBeDir) { LinkOption[] options = IoUtils.getLinkOptions(true); @@ -338,7 +340,7 @@ public class ScpHelper extends AbstractLoggingBean implements SessionHolder<Sess this, header, path, preserve, time, bufferSize); } - receiveStream(header, new LocalFileScpTargetStreamResolver(path, opener), time, preserve, bufferSize); + receiveStream(header, streamFactory.createScpTargetStreamResolver(path, opener), time, preserve, bufferSize); } public void receiveStream(String header, ScpTargetStreamResolver resolver, ScpTimestamp time, boolean preserve, int bufferSize) throws IOException { @@ -558,7 +560,7 @@ public class ScpHelper extends AbstractLoggingBean implements SessionHolder<Sess log.debug("sendFile({})[preserve={},buffer-size={}] Sending file {}", this, preserve, bufferSize, path); } - sendStream(new LocalFileScpSourceStreamResolver(path, opener), preserve, bufferSize); + sendStream(streamFactory.createScpSourceStreamResolver(path, opener), preserve, bufferSize); } public void sendStream(ScpSourceStreamResolver resolver, boolean preserve, int bufferSize) throws IOException { http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/1cd204b7/sshd-core/src/main/java/org/apache/sshd/common/scp/ScpStreamResolverFactory.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/scp/ScpStreamResolverFactory.java b/sshd-core/src/main/java/org/apache/sshd/common/scp/ScpStreamResolverFactory.java new file mode 100644 index 0000000..0dce708 --- /dev/null +++ b/sshd-core/src/main/java/org/apache/sshd/common/scp/ScpStreamResolverFactory.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.sshd.common.scp; + +import java.io.IOException; +import java.nio.file.Path; + +/** + * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> + */ +public interface ScpStreamResolverFactory { + ScpSourceStreamResolver createScpSourceStreamResolver(Path path, ScpFileOpener opener) throws IOException; + + ScpTargetStreamResolver createScpTargetStreamResolver(Path path, ScpFileOpener opener) throws IOException; +} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/1cd204b7/sshd-core/src/main/java/org/apache/sshd/common/scp/ScpStreamResolverFactoryHolder.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/scp/ScpStreamResolverFactoryHolder.java b/sshd-core/src/main/java/org/apache/sshd/common/scp/ScpStreamResolverFactoryHolder.java new file mode 100644 index 0000000..3483629 --- /dev/null +++ b/sshd-core/src/main/java/org/apache/sshd/common/scp/ScpStreamResolverFactoryHolder.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.sshd.common.scp; + +/** + * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> + */ +public interface ScpStreamResolverFactoryHolder { + ScpStreamResolverFactory getScpStreamResolverFactory(); + + void setScpStreamResolverFactory(ScpStreamResolverFactory factory); +} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/1cd204b7/sshd-core/src/main/java/org/apache/sshd/common/scp/helpers/DefaultScpStreamResolverFactory.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/scp/helpers/DefaultScpStreamResolverFactory.java b/sshd-core/src/main/java/org/apache/sshd/common/scp/helpers/DefaultScpStreamResolverFactory.java new file mode 100644 index 0000000..60933e0 --- /dev/null +++ b/sshd-core/src/main/java/org/apache/sshd/common/scp/helpers/DefaultScpStreamResolverFactory.java @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.sshd.common.scp.helpers; + +import java.io.IOException; +import java.nio.file.Path; + +import org.apache.sshd.common.scp.ScpFileOpener; +import org.apache.sshd.common.scp.ScpSourceStreamResolver; +import org.apache.sshd.common.scp.ScpStreamResolverFactory; +import org.apache.sshd.common.scp.ScpTargetStreamResolver; +import org.apache.sshd.common.util.logging.AbstractLoggingBean; + +/** + * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> + */ +public class DefaultScpStreamResolverFactory extends AbstractLoggingBean implements ScpStreamResolverFactory { + public static final DefaultScpStreamResolverFactory INSTANCE = new DefaultScpStreamResolverFactory(); + + public DefaultScpStreamResolverFactory() { + super(); + } + + @Override + public ScpSourceStreamResolver createScpSourceStreamResolver(Path path, ScpFileOpener opener) throws IOException { + return new LocalFileScpSourceStreamResolver(path, opener); + } + + @Override + public ScpTargetStreamResolver createScpTargetStreamResolver(Path path, ScpFileOpener opener) throws IOException { + return new LocalFileScpTargetStreamResolver(path, opener); + } +} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/1cd204b7/sshd-core/src/main/java/org/apache/sshd/server/scp/ScpCommand.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/server/scp/ScpCommand.java b/sshd-core/src/main/java/org/apache/sshd/server/scp/ScpCommand.java index e59a331..3667aa1 100644 --- a/sshd-core/src/main/java/org/apache/sshd/server/scp/ScpCommand.java +++ b/sshd-core/src/main/java/org/apache/sshd/server/scp/ScpCommand.java @@ -31,8 +31,10 @@ import org.apache.sshd.common.file.FileSystemAware; import org.apache.sshd.common.scp.ScpException; import org.apache.sshd.common.scp.ScpFileOpener; import org.apache.sshd.common.scp.ScpHelper; +import org.apache.sshd.common.scp.ScpStreamResolverFactory; import org.apache.sshd.common.scp.ScpTransferEventListener; import org.apache.sshd.common.scp.helpers.DefaultScpFileOpener; +import org.apache.sshd.common.scp.helpers.DefaultScpStreamResolverFactory; import org.apache.sshd.common.session.Session; import org.apache.sshd.common.session.SessionHolder; import org.apache.sshd.common.util.GenericUtils; @@ -61,7 +63,7 @@ public class ScpCommand protected final int sendBufferSize; protected final int receiveBufferSize; protected final ScpFileOpener opener; - + protected final ScpStreamResolverFactory streamFactory; protected boolean optR; protected boolean optT; protected boolean optF; @@ -91,6 +93,7 @@ public class ScpCommand * @param sendSize Size (in bytes) of buffer to use when sending files * @param receiveSize Size (in bytes) of buffer to use when receiving files * @param fileOpener The {@link ScpFileOpener} - if {@code null} then {@link DefaultScpFileOpener} is used + * @param factory The {@link ScpStreamResolverFactory} - if {@code null} then {@link DefaultScpStreamResolverFactory} is used * @param eventListener An {@link ScpTransferEventListener} - may be {@code null} * @see ThreadUtils#newSingleThreadExecutor(String) * @see ScpHelper#MIN_SEND_BUFFER_SIZE @@ -99,7 +102,7 @@ public class ScpCommand public ScpCommand(String command, ExecutorService executorService, boolean shutdownOnExit, int sendSize, int receiveSize, - ScpFileOpener fileOpener, ScpTransferEventListener eventListener) { + ScpFileOpener fileOpener, ScpStreamResolverFactory factory, ScpTransferEventListener eventListener) { name = command; if (executorService == null) { @@ -126,6 +129,7 @@ public class ScpCommand receiveBufferSize = receiveSize; opener = (fileOpener == null) ? DefaultScpFileOpener.INSTANCE : fileOpener; + streamFactory = (factory == null) ? DefaultScpStreamResolverFactory.INSTANCE : factory; listener = (eventListener == null) ? ScpTransferEventListener.EMPTY : eventListener; if (log.isDebugEnabled()) { @@ -269,7 +273,7 @@ public class ScpCommand public void run() { int exitValue = ScpHelper.OK; String exitMessage = null; - ScpHelper helper = new ScpHelper(getServerSession(), in, out, fileSystem, opener, listener); + ScpHelper helper = new ScpHelper(getServerSession(), in, out, fileSystem, opener, streamFactory, listener); try { if (optT) { helper.receive(helper.resolveLocalPath(path), optR, optD, optP, receiveBufferSize); http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/1cd204b7/sshd-core/src/main/java/org/apache/sshd/server/scp/ScpCommandFactory.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/server/scp/ScpCommandFactory.java b/sshd-core/src/main/java/org/apache/sshd/server/scp/ScpCommandFactory.java index 67549b5..b3b2d89 100644 --- a/sshd-core/src/main/java/org/apache/sshd/server/scp/ScpCommandFactory.java +++ b/sshd-core/src/main/java/org/apache/sshd/server/scp/ScpCommandFactory.java @@ -25,6 +25,8 @@ import java.util.concurrent.ExecutorService; import org.apache.sshd.common.scp.ScpFileOpener; import org.apache.sshd.common.scp.ScpFileOpenerHolder; import org.apache.sshd.common.scp.ScpHelper; +import org.apache.sshd.common.scp.ScpStreamResolverFactory; +import org.apache.sshd.common.scp.ScpStreamResolverFactoryHolder; import org.apache.sshd.common.scp.ScpTransferEventListener; import org.apache.sshd.common.util.EventListenerUtils; import org.apache.sshd.common.util.ObjectBuilder; @@ -40,7 +42,12 @@ import org.apache.sshd.server.CommandFactory; * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> * @see ScpCommand */ -public class ScpCommandFactory implements ScpFileOpenerHolder, CommandFactory, Cloneable, ExecutorServiceConfigurer { +public class ScpCommandFactory + implements ScpFileOpenerHolder, + ScpStreamResolverFactoryHolder, + CommandFactory, + Cloneable, + ExecutorServiceConfigurer { /** * A useful {@link ObjectBuilder} for {@link ScpCommandFactory} */ @@ -56,6 +63,11 @@ public class ScpCommandFactory implements ScpFileOpenerHolder, CommandFactory, C return this; } + public Builder withScpStreamResolverFactory(ScpStreamResolverFactory streamFactory) { + factory.setScpStreamResolverFactory(streamFactory); + return this; + } + public Builder withDelegate(CommandFactory delegate) { factory.setDelegateCommandFactory(delegate); return this; @@ -105,6 +117,7 @@ public class ScpCommandFactory implements ScpFileOpenerHolder, CommandFactory, C private ExecutorService executors; private boolean shutdownExecutor; private ScpFileOpener fileOpener; + private ScpStreamResolverFactory streamFactory; private int sendBufferSize = ScpHelper.MIN_SEND_BUFFER_SIZE; private int receiveBufferSize = ScpHelper.MIN_RECEIVE_BUFFER_SIZE; private Collection<ScpTransferEventListener> listeners = new CopyOnWriteArraySet<>(); @@ -124,6 +137,16 @@ public class ScpCommandFactory implements ScpFileOpenerHolder, CommandFactory, C this.fileOpener = fileOpener; } + @Override + public ScpStreamResolverFactory getScpStreamResolverFactory() { + return streamFactory; + } + + @Override + public void setScpStreamResolverFactory(ScpStreamResolverFactory streamFactory) { + this.streamFactory = streamFactory; + } + public CommandFactory getDelegateCommandFactory() { return delegate; } @@ -242,7 +265,7 @@ public class ScpCommandFactory implements ScpFileOpenerHolder, CommandFactory, C return new ScpCommand(command, getExecutorService(), isShutdownOnExit(), getSendBufferSize(), getReceiveBufferSize(), - getScpFileOpener(), listenerProxy); + getScpFileOpener(), getScpStreamResolverFactory(), listenerProxy); } CommandFactory factory = getDelegateCommandFactory(); http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/1cd204b7/sshd-core/src/test/java/org/apache/sshd/client/scp/ScpTest.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/test/java/org/apache/sshd/client/scp/ScpTest.java b/sshd-core/src/test/java/org/apache/sshd/client/scp/ScpTest.java index 42907d6..56ee962 100644 --- a/sshd-core/src/test/java/org/apache/sshd/client/scp/ScpTest.java +++ b/sshd-core/src/test/java/org/apache/sshd/client/scp/ScpTest.java @@ -53,8 +53,10 @@ import org.apache.sshd.common.random.Random; import org.apache.sshd.common.scp.ScpException; import org.apache.sshd.common.scp.ScpFileOpener; import org.apache.sshd.common.scp.ScpHelper; +import org.apache.sshd.common.scp.ScpStreamResolverFactory; import org.apache.sshd.common.scp.ScpTransferEventListener; import org.apache.sshd.common.scp.helpers.DefaultScpFileOpener; +import org.apache.sshd.common.scp.helpers.DefaultScpStreamResolverFactory; import org.apache.sshd.common.session.Session; import org.apache.sshd.common.util.GenericUtils; import org.apache.sshd.common.util.OsUtils; @@ -768,8 +770,9 @@ public class ScpTest extends BaseTestSupport { private ExitCallback delegate; InternalScpCommand(String command, ExecutorService executorService, boolean shutdownOnExit, - int sendSize, int receiveSize, ScpFileOpener opener, ScpTransferEventListener eventListener) { - super(command, executorService, shutdownOnExit, sendSize, receiveSize, opener, eventListener); + int sendSize, int receiveSize, ScpFileOpener opener, + ScpStreamResolverFactory factory, ScpTransferEventListener eventListener) { + super(command, executorService, shutdownOnExit, sendSize, receiveSize, opener, factory, eventListener); } @Override @@ -808,7 +811,9 @@ public class ScpTest extends BaseTestSupport { return new InternalScpCommand(command, getExecutorService(), isShutdownOnExit(), getSendBufferSize(), getReceiveBufferSize(), - DefaultScpFileOpener.INSTANCE, ScpTransferEventListener.EMPTY); + DefaultScpFileOpener.INSTANCE, + DefaultScpStreamResolverFactory.INSTANCE, + ScpTransferEventListener.EMPTY); } });
