Issue #9309 - More comprehensive escaping of command line options
Signed-off-by: Joakim Erdfelt <joakim.erdfelt@gmail.com>
This commit is contained in:
parent
016de2faeb
commit
45fdebc0fb
|
@ -19,6 +19,17 @@ import java.util.List;
|
||||||
|
|
||||||
public class CommandLineBuilder
|
public class CommandLineBuilder
|
||||||
{
|
{
|
||||||
|
// Matrix of 7-bit characters that needs escaping on command line.
|
||||||
|
private static final boolean[] NEEDS_ESCAPING = new boolean[127];
|
||||||
|
|
||||||
|
static
|
||||||
|
{
|
||||||
|
for (char c : " %$\\{}[]()\"|<>&;`!".toCharArray())
|
||||||
|
{
|
||||||
|
NEEDS_ESCAPING[c] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static File findExecutable(File root, String path)
|
public static File findExecutable(File root, String path)
|
||||||
{
|
{
|
||||||
String npath = path.replace('/', File.separatorChar);
|
String npath = path.replace('/', File.separatorChar);
|
||||||
|
@ -59,21 +70,28 @@ public class CommandLineBuilder
|
||||||
*
|
*
|
||||||
* @param arg the argument to quote
|
* @param arg the argument to quote
|
||||||
* @return the quoted and escaped argument
|
* @return the quoted and escaped argument
|
||||||
|
* @deprecated use {@link #escape(String) instead}
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public static String quote(String arg)
|
public static String quote(String arg)
|
||||||
{
|
{
|
||||||
boolean needsQuoting = (arg.indexOf(' ') >= 0) || (arg.indexOf('"') >= 0);
|
return escape(arg);
|
||||||
if (!needsQuoting)
|
|
||||||
{
|
|
||||||
return arg;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Escape the raw string to make it suitable for use on a command line.
|
||||||
|
*
|
||||||
|
* @param arg the argument to escape
|
||||||
|
* @return the escaped argument
|
||||||
|
*/
|
||||||
|
public static String escape(String arg)
|
||||||
|
{
|
||||||
StringBuilder buf = new StringBuilder();
|
StringBuilder buf = new StringBuilder();
|
||||||
// buf.append('"');
|
|
||||||
boolean escaped = false;
|
boolean escaped = false;
|
||||||
boolean quoted = false;
|
boolean quoted = false;
|
||||||
for (char c : arg.toCharArray())
|
for (char c : arg.toCharArray())
|
||||||
{
|
{
|
||||||
if (!quoted && !escaped && ((c == '"') || (c == ' ')))
|
if (!quoted && !escaped && NEEDS_ESCAPING[c])
|
||||||
{
|
{
|
||||||
buf.append("\\");
|
buf.append("\\");
|
||||||
}
|
}
|
||||||
|
@ -85,7 +103,6 @@ public class CommandLineBuilder
|
||||||
escaped = (c == '\\');
|
escaped = (c == '\\');
|
||||||
buf.append(c);
|
buf.append(c);
|
||||||
}
|
}
|
||||||
// buf.append('"');
|
|
||||||
return buf.toString();
|
return buf.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,7 +130,7 @@ public class CommandLineBuilder
|
||||||
{
|
{
|
||||||
if (arg != null)
|
if (arg != null)
|
||||||
{
|
{
|
||||||
args.add(quote(arg));
|
args.add(escape(arg));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,11 +153,11 @@ public class CommandLineBuilder
|
||||||
{
|
{
|
||||||
if ((value != null) && (value.length() > 0))
|
if ((value != null) && (value.length() > 0))
|
||||||
{
|
{
|
||||||
args.add(quote(name + "=" + value));
|
args.add(escape(name + "=" + value));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
args.add(quote(name));
|
args.add(escape(name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,7 +197,7 @@ public class CommandLineBuilder
|
||||||
{
|
{
|
||||||
buf.append(delim);
|
buf.append(delim);
|
||||||
}
|
}
|
||||||
buf.append(quote(arg));
|
buf.append(arg); // we assume escaping has occurred during addArg
|
||||||
}
|
}
|
||||||
|
|
||||||
return buf.toString();
|
return buf.toString();
|
||||||
|
|
|
@ -21,54 +21,49 @@ import static org.hamcrest.Matchers.is;
|
||||||
|
|
||||||
public class CommandLineBuilderTest
|
public class CommandLineBuilderTest
|
||||||
{
|
{
|
||||||
private CommandLineBuilder cmd = new CommandLineBuilder("java");
|
|
||||||
|
|
||||||
@BeforeEach
|
|
||||||
public void setUp()
|
|
||||||
{
|
|
||||||
cmd.addEqualsArg("-Djava.io.tmpdir", "/home/java/temp dir/");
|
|
||||||
cmd.addArg("--version");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSimpleCommandline()
|
public void testSimpleCommandline()
|
||||||
{
|
{
|
||||||
|
CommandLineBuilder cmd = new CommandLineBuilder("java");
|
||||||
|
cmd.addEqualsArg("-Djava.io.tmpdir", "/home/java/temp dir/");
|
||||||
|
cmd.addArg("--version");
|
||||||
assertThat(cmd.toString(), is("java -Djava.io.tmpdir=/home/java/temp\\ dir/ --version"));
|
assertThat(cmd.toString(), is("java -Djava.io.tmpdir=/home/java/temp\\ dir/ --version"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testQuotingSimple()
|
public void testEscapedSimple()
|
||||||
{
|
{
|
||||||
assertQuoting("/opt/jetty", "/opt/jetty");
|
assertEscaping("/opt/jetty", "/opt/jetty");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testQuotingSpaceInPath()
|
public void testEscapedSpaceInPath()
|
||||||
{
|
{
|
||||||
assertQuoting("/opt/jetty 7/home", "/opt/jetty\\ 7/home");
|
assertEscaping("/opt/jetty 7/home", "/opt/jetty\\ 7/home");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testQuotingSpaceAndQuotesInPath()
|
public void testEscapedSpaceAndQuotesInPath()
|
||||||
{
|
{
|
||||||
assertQuoting("/opt/jetty 7 \"special\"/home", "/opt/jetty\\ 7\\ \\\"special\\\"/home");
|
assertEscaping("/opt/jetty 7 \"special\"/home", "/opt/jetty\\ 7\\ \\\"special\\\"/home");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testToStringIsQuotedEvenIfArgsAreNotQuotedForProcessBuilder()
|
public void testEscapedFormattingString()
|
||||||
{
|
{
|
||||||
System.out.println(cmd.toString());
|
assertEscaping("%{client}a - %u %{dd/MMM/yyyy:HH:mm:ss ZZZ|GMT}t \"%r\" %s %O \"%{Referer}i\" \"%{User-Agent}i\"",
|
||||||
|
"\\%\\{client\\}a\\ -\\ \\%u\\ \\%\\{dd/MMM/yyyy:HH:mm:ss\\ ZZZ\\|GMT\\}t\\ \\\"\\%r\\\"\\ \\%s\\ \\%O\\ \\\"\\%\\{Referer\\}i\\\"\\ \\\"\\%\\{User-Agent\\}i\\\"");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testQuoteQuotationMarks()
|
public void testEscapeQuotationMarks()
|
||||||
{
|
{
|
||||||
assertQuoting("-XX:OnOutOfMemoryError='kill -9 %p'", "-XX:OnOutOfMemoryError='kill -9 %p'");
|
assertEscaping("-XX:OnOutOfMemoryError='kill -9 %p'", "-XX:OnOutOfMemoryError='kill -9 %p'");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertQuoting(String raw, String expected)
|
private void assertEscaping(String raw, String expected)
|
||||||
{
|
{
|
||||||
String actual = CommandLineBuilder.quote(raw);
|
String actual = CommandLineBuilder.escape(raw);
|
||||||
assertThat("Quoted version of [" + raw + "]", actual, is(expected));
|
assertThat("Escaped version of [" + raw + "]", actual, is(expected));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue