You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by lg...@apache.org on 2022/02/08 16:37:40 UTC
[mina-sshd] 05/05: Added support for quoted arguments in SftpCommandMain
This is an automated email from the ASF dual-hosted git repository.
lgoldstein pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mina-sshd.git
commit 82c95e18d3f9a0b960cd0a65b9cd2c37dc0d9d2e
Author: Lyor Goldstein <lg...@apache.org>
AuthorDate: Sat Feb 5 07:46:47 2022 +0200
Added support for quoted arguments in SftpCommandMain
---
.../main/java/org/apache/sshd/cli/CliSupport.java | 72 +++++++++++++++++
.../apache/sshd/cli/client/SftpCommandMain.java | 43 +++-------
.../CliSupportSplitCommandLineArgumentsTest.java | 94 ++++++++++++++++++++++
3 files changed, 179 insertions(+), 30 deletions(-)
diff --git a/sshd-cli/src/main/java/org/apache/sshd/cli/CliSupport.java b/sshd-cli/src/main/java/org/apache/sshd/cli/CliSupport.java
index f7306e7..e7cda7d 100644
--- a/sshd-cli/src/main/java/org/apache/sshd/cli/CliSupport.java
+++ b/sshd-cli/src/main/java/org/apache/sshd/cli/CliSupport.java
@@ -20,10 +20,14 @@ package org.apache.sshd.cli;
import java.io.IOException;
import java.io.PrintStream;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
import java.net.SocketAddress;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
+import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
@@ -341,4 +345,72 @@ public abstract class CliSupport {
return new ArrayList<>(available);
}
+
+ public static String[] splitCommandLineArguments(String line) {
+ line = GenericUtils.trimToEmpty(line);
+ if (GenericUtils.isBlank(line)) {
+ return GenericUtils.EMPTY_STRING_ARRAY;
+ }
+
+ Collection<String> args = Collections.emptyList();
+ for (int index = 0; index < GenericUtils.QUOTES.length(); index++) {
+ char delim = GenericUtils.QUOTES.charAt(index);
+ int startPos = line.indexOf(delim);
+ int endPos = -1;
+ if (startPos >= 0) {
+ endPos = line.indexOf(delim, startPos + 1);
+ }
+
+ if ((startPos >= 0) && (endPos > startPos)) {
+ if (GenericUtils.isEmpty(args)) {
+ args = new LinkedList<>();
+ }
+
+ String prefix = (startPos > 0) ? line.substring(0, startPos).trim() : "";
+ String[] extra = GenericUtils.split(prefix, ' ');
+ if (!GenericUtils.isEmpty(extra)) {
+ args.addAll(Arrays.asList(extra));
+ }
+
+ String value = line.substring(startPos + 1, endPos);
+ args.add(value);
+
+ line = (endPos < (line.length() - 1)) ? line.substring(endPos + 1).trim() : "";
+ if (GenericUtils.isBlank(line)) {
+ break;
+ }
+
+ index = -1; // start delimiters again
+ }
+ }
+
+ // see if any leftovers
+ String[] extra = GenericUtils.split(line, ' ');
+ if (GenericUtils.isEmpty(args)) {
+ return extra;
+ }
+
+ if (!GenericUtils.isEmpty(extra)) {
+ if (GenericUtils.isEmpty(args)) {
+ args = new LinkedList<>();
+ }
+ args.addAll(Arrays.asList(extra));
+ }
+
+ return args.toArray(GenericUtils.EMPTY_STRING_ARRAY);
+ }
+
+ public static void printFieldsValues(Object info, PrintStream stdout) throws Exception {
+ Field[] fields = info.getClass().getFields();
+ for (Field f : fields) {
+ String name = f.getName();
+ int mod = f.getModifiers();
+ if (Modifier.isStatic(mod)) {
+ continue;
+ }
+
+ Object value = f.get(info);
+ stdout.append(" ").append(name).append(": ").println(value);
+ }
+ }
}
diff --git a/sshd-cli/src/main/java/org/apache/sshd/cli/client/SftpCommandMain.java b/sshd-cli/src/main/java/org/apache/sshd/cli/client/SftpCommandMain.java
index 2e98012..e9e6a9c 100644
--- a/sshd-cli/src/main/java/org/apache/sshd/cli/client/SftpCommandMain.java
+++ b/sshd-cli/src/main/java/org/apache/sshd/cli/client/SftpCommandMain.java
@@ -26,8 +26,6 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintStream;
-import java.lang.reflect.Field;
-import java.lang.reflect.Modifier;
import java.nio.channels.Channel;
import java.nio.charset.StandardCharsets;
import java.nio.file.DirectoryStream;
@@ -44,6 +42,7 @@ import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import org.apache.sshd.cli.CliLogger;
+import org.apache.sshd.cli.CliSupport;
import org.apache.sshd.cli.client.helper.SftpFileTransferProgressOutputStream;
import org.apache.sshd.client.ClientFactoryManager;
import org.apache.sshd.client.session.ClientSession;
@@ -719,7 +718,7 @@ public class SftpCommandMain extends SshClientCliSupport implements SftpClientHo
public boolean executeCommand(
String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr)
throws Exception {
- String[] comps = GenericUtils.split(args, ' ');
+ String[] comps = CliSupport.splitCommandLineArguments(args);
int numComps = GenericUtils.length(comps);
String pathArg = (numComps <= 0) ? null : GenericUtils.trimToEmpty(comps[numComps - 1]);
String flags = (numComps >= 2) ? GenericUtils.trimToEmpty(comps[0]) : null;
@@ -763,7 +762,7 @@ public class SftpCommandMain extends SshClientCliSupport implements SftpClientHo
public boolean executeCommand(
String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr)
throws Exception {
- String[] comps = GenericUtils.split(args, ' ');
+ String[] comps = CliSupport.splitCommandLineArguments(args);
int numComps = GenericUtils.length(comps);
String pathArg = (numComps <= 0) ? null : GenericUtils.trimToEmpty(comps[numComps - 1]);
String flags = (numComps >= 2) ? GenericUtils.trimToEmpty(comps[0]) : null;
@@ -818,7 +817,7 @@ public class SftpCommandMain extends SshClientCliSupport implements SftpClientHo
public boolean executeCommand(
String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr)
throws Exception {
- String[] comps = GenericUtils.split(args, ' ');
+ String[] comps = CliSupport.splitCommandLineArguments(args);
int numArgs = GenericUtils.length(comps);
ValidateUtils.checkTrue(numArgs >= 1, "No arguments");
ValidateUtils.checkTrue(numArgs <= 2, "Too many arguments: %s", args);
@@ -932,7 +931,7 @@ public class SftpCommandMain extends SshClientCliSupport implements SftpClientHo
public boolean executeCommand(
String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr)
throws Exception {
- String[] comps = GenericUtils.split(args, ' ');
+ String[] comps = CliSupport.splitCommandLineArguments(args);
ValidateUtils.checkTrue(GenericUtils.length(comps) == 2, "Invalid number of arguments: %s", args);
String oldPath = resolveRemotePath(GenericUtils.trimToEmpty(comps[0]));
@@ -959,7 +958,7 @@ public class SftpCommandMain extends SshClientCliSupport implements SftpClientHo
public boolean executeCommand(
String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr)
throws Exception {
- String[] comps = GenericUtils.split(args, ' ');
+ String[] comps = CliSupport.splitCommandLineArguments(args);
int numArgs = GenericUtils.length(comps);
ValidateUtils.checkTrue(numArgs <= 1, "Invalid number of arguments: %s", args);
@@ -967,7 +966,7 @@ public class SftpCommandMain extends SshClientCliSupport implements SftpClientHo
OpenSSHLimitsExtension ext = sftp.getExtension(OpenSSHLimitsExtension.class);
ValidateUtils.checkTrue(ext.isSupported(), "Extension not supported by server: %s", ext.getName());
OpenSSHLimitsExtensionInfo info = ext.limits();
- printFieldsValues(info, stdout);
+ CliSupport.printFieldsValues(info, stdout);
return false;
}
}
@@ -988,7 +987,7 @@ public class SftpCommandMain extends SshClientCliSupport implements SftpClientHo
public boolean executeCommand(
String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr)
throws Exception {
- String[] comps = GenericUtils.split(args, ' ');
+ String[] comps = CliSupport.splitCommandLineArguments(args);
int numArgs = GenericUtils.length(comps);
ValidateUtils.checkTrue(numArgs <= 1, "Invalid number of arguments: %s", args);
@@ -999,7 +998,7 @@ public class SftpCommandMain extends SshClientCliSupport implements SftpClientHo
String remPath = resolveRemotePath(
(numArgs >= 1) ? GenericUtils.trimToEmpty(comps[0]) : GenericUtils.trimToEmpty(args));
OpenSSHStatExtensionInfo info = ext.stat(remPath);
- printFieldsValues(info, stdout);
+ CliSupport.printFieldsValues(info, stdout);
return false;
}
}
@@ -1020,7 +1019,7 @@ public class SftpCommandMain extends SshClientCliSupport implements SftpClientHo
public boolean executeCommand(
String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr)
throws Exception {
- String[] comps = GenericUtils.split(args, ' ');
+ String[] comps = CliSupport.splitCommandLineArguments(args);
ValidateUtils.checkTrue(GenericUtils.length(comps) <= 1, "Invalid number of arguments: %s", args);
String path = GenericUtils.trimToEmpty(resolveRemotePath(args));
@@ -1046,7 +1045,7 @@ public class SftpCommandMain extends SshClientCliSupport implements SftpClientHo
@Override
public boolean executeCommand(String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr)
throws Exception {
- String[] comps = GenericUtils.split(args, ' ');
+ String[] comps = CliSupport.splitCommandLineArguments(args);
ValidateUtils.checkTrue(GenericUtils.length(comps) <= 1, "Invalid number of arguments: %s", args);
String path = GenericUtils.trimToEmpty(resolveRemotePath(args));
@@ -1202,7 +1201,7 @@ public class SftpCommandMain extends SshClientCliSupport implements SftpClientHo
}
protected void executeCommand(String args, boolean upload, PrintStream stdout) throws IOException {
- String[] comps = GenericUtils.split(args, ' ');
+ String[] comps = CliSupport.splitCommandLineArguments(args);
int numArgs = GenericUtils.length(comps);
ValidateUtils.checkTrue((numArgs >= 1) && (numArgs <= 3), "Invalid number of arguments: %s", args);
@@ -1325,7 +1324,7 @@ public class SftpCommandMain extends SshClientCliSupport implements SftpClientHo
public boolean executeCommand(
String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr)
throws Exception {
- String[] comps = GenericUtils.split(args, ' ');
+ String[] comps = CliSupport.splitCommandLineArguments(args);
int numArgs = GenericUtils.length(comps);
if (numArgs <= 0) {
stdout.append(" ").append(getName()).append(' ').println(isShowProgress() ? "on" : "off");
@@ -1345,20 +1344,4 @@ public class SftpCommandMain extends SshClientCliSupport implements SftpClientHo
return false;
}
}
-
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
- public static void printFieldsValues(Object info, PrintStream stdout) throws Exception {
- Field[] fields = info.getClass().getFields();
- for (Field f : fields) {
- String name = f.getName();
- int mod = f.getModifiers();
- if (Modifier.isStatic(mod)) {
- continue;
- }
-
- Object value = f.get(info);
- stdout.append(" ").append(name).append(": ").println(value);
- }
- }
}
diff --git a/sshd-cli/src/test/java/org/apache/sshd/cli/CliSupportSplitCommandLineArgumentsTest.java b/sshd-cli/src/test/java/org/apache/sshd/cli/CliSupportSplitCommandLineArgumentsTest.java
new file mode 100644
index 0000000..dcdd29b
--- /dev/null
+++ b/sshd-cli/src/test/java/org/apache/sshd/cli/CliSupportSplitCommandLineArgumentsTest.java
@@ -0,0 +1,94 @@
+/*
+ * 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.cli;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.util.test.BaseTestSupport;
+import org.apache.sshd.util.test.JUnit4ClassRunnerWithParametersFactory;
+import org.apache.sshd.util.test.NoIoTestCase;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+import org.junit.runners.MethodSorters;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+import org.junit.runners.Parameterized.UseParametersRunnerFactory;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Category({ NoIoTestCase.class })
+@RunWith(Parameterized.class) // see https://github.com/junit-team/junit/wiki/Parameterized-tests
+@UseParametersRunnerFactory(JUnit4ClassRunnerWithParametersFactory.class)
+public class CliSupportSplitCommandLineArgumentsTest extends BaseTestSupport {
+ private final String line;
+ private final String[] expected;
+
+ public CliSupportSplitCommandLineArgumentsTest(String line, String[] expected) {
+ this.line = line;
+ this.expected = expected;
+ }
+
+ @Parameters(name = "{0}")
+ public static List<Object[]> parameters() {
+ return new ArrayList<Object[]>() {
+ // not serializing it
+ private static final long serialVersionUID = 1L;
+
+ {
+ addTestCase(null, GenericUtils.EMPTY_STRING_ARRAY);
+ addTestCase("", GenericUtils.EMPTY_STRING_ARRAY);
+ addTestCase(" ", GenericUtils.EMPTY_STRING_ARRAY);
+ addPaddedTestCase("hello", "hello");
+ addPaddedTestCase("hello world", "hello", "world");
+
+ for (int index = 0; index < GenericUtils.QUOTES.length(); index++) {
+ char delim = GenericUtils.QUOTES.charAt(index);
+ addPaddedTestCase(delim + "hello world" + delim, "hello world");
+ addPaddedTestCase(delim + "hello" + delim + " world", "hello", "world");
+ addPaddedTestCase("hello " + delim + "world" + delim, "hello", "world");
+ addPaddedTestCase(delim + "hello" + delim + " " + delim + "world" + delim, "hello", "world");
+ }
+ }
+
+ private void addPaddedTestCase(String line, String... expected) {
+ addTestCase(line, expected);
+ addTestCase(" " + line, expected);
+ addTestCase(line + " ", expected);
+ addTestCase(" " + line + " ", expected);
+ }
+
+ private void addTestCase(String line, String... expected) {
+ add(new Object[] { line, expected });
+ }
+ };
+ }
+
+ @Test
+ public void testSplitCommandLineArguments() {
+ String[] actual = CliSupport.splitCommandLineArguments(line);
+ assertArrayEquals(expected, actual);
+ }
+}