Fri, 15 May 2015 16:36:25 +0200
8049300: jjs scripting: need way to quote $EXEC command arguments to protect spaces
Summary: honor quoting with "" and '' as well as escaped spaces
Reviewed-by: hannesw, sundar
src/jdk/nashorn/internal/runtime/ScriptingFunctions.java | file | annotate | diff | comparison | revisions |
1.1 --- a/src/jdk/nashorn/internal/runtime/ScriptingFunctions.java Mon Apr 20 10:39:55 2015 +0200 1.2 +++ b/src/jdk/nashorn/internal/runtime/ScriptingFunctions.java Fri May 15 16:36:25 2015 +0200 1.3 @@ -1,5 +1,5 @@ 1.4 /* 1.5 - * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 1.6 + * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. 1.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.8 * 1.9 * This code is free software; you can redistribute it and/or modify it 1.10 @@ -34,10 +34,13 @@ 1.11 import java.io.IOException; 1.12 import java.io.InputStreamReader; 1.13 import java.io.OutputStreamWriter; 1.14 +import java.io.StreamTokenizer; 1.15 +import java.io.StringReader; 1.16 import java.lang.invoke.MethodHandle; 1.17 import java.lang.invoke.MethodHandles; 1.18 +import java.util.ArrayList; 1.19 +import java.util.List; 1.20 import java.util.Map; 1.21 -import java.util.StringTokenizer; 1.22 1.23 /** 1.24 * Global functions supported only in scripting mode. 1.25 @@ -133,15 +136,8 @@ 1.26 // Current global is need to fetch additional inputs and for additional results. 1.27 final ScriptObject global = Context.getGlobal(); 1.28 1.29 - // Break exec string into tokens. 1.30 - final StringTokenizer tokenizer = new StringTokenizer(JSType.toString(string)); 1.31 - final String[] cmdArray = new String[tokenizer.countTokens()]; 1.32 - for (int i = 0; tokenizer.hasMoreTokens(); i++) { 1.33 - cmdArray[i] = tokenizer.nextToken(); 1.34 - } 1.35 - 1.36 // Set up initial process. 1.37 - final ProcessBuilder processBuilder = new ProcessBuilder(cmdArray); 1.38 + final ProcessBuilder processBuilder = new ProcessBuilder(tokenizeCommandLine(JSType.toString(string))); 1.39 1.40 // Current ENV property state. 1.41 final Object env = global.get(ENV_NAME); 1.42 @@ -239,4 +235,43 @@ 1.43 private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) { 1.44 return MH.findStatic(MethodHandles.lookup(), ScriptingFunctions.class, name, MH.type(rtype, types)); 1.45 } 1.46 + 1.47 + /** 1.48 + * Break an exec string into tokens, honoring quoted arguments and escaped 1.49 + * spaces. 1.50 + * 1.51 + * @param execString a {@link String} with the command line to execute. 1.52 + * @return a {@link List} of {@link String}s representing the tokens that 1.53 + * constitute the command line. 1.54 + * @throws IOException in case {@link StreamTokenizer#nextToken()} raises it. 1.55 + */ 1.56 + private static List<String> tokenizeCommandLine(final String execString) throws IOException { 1.57 + final StreamTokenizer tokenizer = new StreamTokenizer(new StringReader(execString)); 1.58 + tokenizer.resetSyntax(); 1.59 + tokenizer.wordChars(0, 255); 1.60 + tokenizer.whitespaceChars(0, ' '); 1.61 + tokenizer.commentChar('#'); 1.62 + tokenizer.quoteChar('"'); 1.63 + tokenizer.quoteChar('\''); 1.64 + final List<String> cmdList = new ArrayList<>(); 1.65 + final StringBuilder toAppend = new StringBuilder(); 1.66 + while (tokenizer.nextToken() != StreamTokenizer.TT_EOF) { 1.67 + final String s = tokenizer.sval; 1.68 + // The tokenizer understands about honoring quoted strings and recognizes 1.69 + // them as one token that possibly contains multiple space-separated words. 1.70 + // It does not recognize quoted spaces, though, and will split after the 1.71 + // escaping \ character. This is handled here. 1.72 + if (s.endsWith("\\")) { 1.73 + // omit trailing \, append space instead 1.74 + toAppend.append(s.substring(0, s.length() - 1)).append(' '); 1.75 + } else { 1.76 + cmdList.add(toAppend.append(s).toString()); 1.77 + toAppend.setLength(0); 1.78 + } 1.79 + } 1.80 + if (toAppend.length() != 0) { 1.81 + cmdList.add(toAppend.toString()); 1.82 + } 1.83 + return cmdList; 1.84 + } 1.85 }