You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2025/08/20 19:21:55 UTC

(camel) branch camel-4.14.x updated: CAMEL-22362: camel-exec - Use quote safe arg parser (#18956)

This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch camel-4.14.x
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/camel-4.14.x by this push:
     new 36296295736 CAMEL-22362: camel-exec - Use quote safe arg parser (#18956)
36296295736 is described below

commit 36296295736c58a8e0a7116cef5b79c9be5c0cd3
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Wed Aug 20 21:20:34 2025 +0200

    CAMEL-22362: camel-exec - Use quote safe arg parser (#18956)
---
 .../camel/component/exec/impl/ExecParseUtils.java  | 83 +++-------------------
 .../component/exec/impl/ExecParseUtilsTest.java    | 70 +++---------------
 2 files changed, 17 insertions(+), 136 deletions(-)

diff --git a/components/camel-exec/src/main/java/org/apache/camel/component/exec/impl/ExecParseUtils.java b/components/camel-exec/src/main/java/org/apache/camel/component/exec/impl/ExecParseUtils.java
index 65bb68b8dc6..7c1f09f2aef 100644
--- a/components/camel-exec/src/main/java/org/apache/camel/component/exec/impl/ExecParseUtils.java
+++ b/components/camel-exec/src/main/java/org/apache/camel/component/exec/impl/ExecParseUtils.java
@@ -17,97 +17,30 @@
 package org.apache.camel.component.exec.impl;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 import java.util.StringTokenizer;
 
+import org.apache.camel.util.StringQuoteHelper;
+
 /**
  * Utility class for parsing, used by the Camel Exec component.<br>
  * Note: the class should be dropped, when the commons-exec library implements similar functionality.
  */
 public final class ExecParseUtils {
 
-    public static final String WHITESPACE = " ";
-
-    public static final String QUOTE_CHAR = "\"";
-
     private ExecParseUtils() {
     }
 
-    /**
-     * Splits the input line string by {@link #WHITESPACE}. Supports quoting the white-spaces with a
-     * {@link #QUOTE_CHAR}. A quote itself can also be enclosed within #{@link #QUOTE_CHAR}#{@link #QUOTE_CHAR}. More
-     * than two double-quotes in a sequence is not allowed. Nested quotes are not allowed.<br>
-     * E.g. The string <code>"arg 1"  arg2<code> will return the tokens <code>arg 1</code>, <code>arg2</code><br>
-     * The string <code>""arg 1""  "arg2" arg 3<code> will return the tokens <code>"arg 1"</code> ,
-     * <code>arg2</code>,<code>arg</code> and <code>3</code> <br>
-     *
-     * @param  input the input to split.
-     * @return       a not-null list of tokens
-     */
     public static List<String> splitToWhiteSpaceSeparatedTokens(String input) {
+        List<String> answer = new ArrayList<>();
         if (input == null) {
-            return new ArrayList<>();
-        }
-        StringTokenizer tokenizer = new StringTokenizer(input.trim(), QUOTE_CHAR + WHITESPACE, true);
-        List<String> tokens = new ArrayList<>();
-
-        StringBuilder quotedText = new StringBuilder();
-
-        while (tokenizer.hasMoreTokens()) {
-            String token = tokenizer.nextToken();
-            if (QUOTE_CHAR.equals(token)) {
-                // if we have a quote, add the next tokens to the quoted text
-                // until the quoting has finished
-                quotedText.append(QUOTE_CHAR);
-                String buffer = quotedText.toString();
-                if (isSingleQuoted(buffer) || isDoubleQuoted(buffer)) {
-                    tokens.add(buffer.substring(1, buffer.length() - 1));
-                    quotedText = new StringBuilder();
-                }
-            } else if (WHITESPACE.equals(token)) {
-                // a white space, if in quote, add the white space, otherwise
-                // skip it
-                if (quotedText.length() > 0) {
-                    quotedText.append(WHITESPACE);
-                }
-            } else {
-                if (quotedText.length() > 0) {
-                    quotedText.append(token);
-                } else {
-                    tokens.add(token);
-                }
-            }
+            return answer;
         }
-        if (quotedText.length() > 0) {
-            throw new IllegalArgumentException("Invalid quoting found in args " + quotedText);
-        }
-        return tokens;
-    }
-
-    /**
-     * Tests if the input is enclosed within {@link #QUOTE_CHAR} characters
-     *
-     * @param  input a not null String
-     * @return       true if the regular expression is matched
-     */
-    protected static boolean isSingleQuoted(String input) {
-        if (input == null || input.isBlank()) {
-            return false;
-        }
-        return input.matches("(^" + QUOTE_CHAR + "{1}([^" + QUOTE_CHAR + "]+)" + QUOTE_CHAR + "{1})");
-    }
 
-    /**
-     * Tests if the input is enclosed within a double-{@link #QUOTE_CHAR} string
-     *
-     * @param  input a not null String
-     * @return       true if the regular expression is matched
-     */
-    protected static boolean isDoubleQuoted(String input) {
-        if (input == null || input.isBlank()) {
-            return false;
-        }
-        return input.matches("(^" + QUOTE_CHAR + "{2}([^" + QUOTE_CHAR + "]+)" + QUOTE_CHAR + "{2})");
+        String[] arr = StringQuoteHelper.splitSafeQuote(input, ' ', true, false);
+        Collections.addAll(answer, arr);
+        return answer;
     }
 
     public static List<Integer> splitCommaSeparatedToListOfInts(String commaSeparatedInts) {
diff --git a/components/camel-exec/src/test/java/org/apache/camel/component/exec/impl/ExecParseUtilsTest.java b/components/camel-exec/src/test/java/org/apache/camel/component/exec/impl/ExecParseUtilsTest.java
index 9e78e9018d9..9070f41ba7f 100644
--- a/components/camel-exec/src/test/java/org/apache/camel/component/exec/impl/ExecParseUtilsTest.java
+++ b/components/camel-exec/src/test/java/org/apache/camel/component/exec/impl/ExecParseUtilsTest.java
@@ -20,64 +20,14 @@ import java.util.List;
 
 import org.junit.jupiter.api.Test;
 
-import static org.apache.camel.component.exec.impl.ExecParseUtils.isDoubleQuoted;
-import static org.apache.camel.component.exec.impl.ExecParseUtils.isSingleQuoted;
 import static org.apache.camel.component.exec.impl.ExecParseUtils.splitToWhiteSpaceSeparatedTokens;
 import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.junit.jupiter.api.Assertions.assertTrue;
 
 /**
  * Tests for {@link ExecParseUtils}
  */
 public class ExecParseUtilsTest {
 
-    @Test
-    public void testSingleQuoted() {
-        assertTrue(isSingleQuoted("\"c:\\program files\\test\""));
-    }
-
-    @Test
-    public void testSingleQuoted2() {
-        assertTrue(isSingleQuoted("\"with space\""));
-    }
-
-    @Test
-    public void testSingleQuotedNegative() {
-        assertFalse(isSingleQuoted("arg 0"));
-    }
-
-    @Test
-    public void testSingleQuotedNegative2() {
-        assertFalse(isSingleQuoted("\" \" space not allowed between quotes \""));
-    }
-
-    @Test
-    public void testSingleQuotedNegative3() {
-        assertFalse(isSingleQuoted("\"\"double quoted is not single quoted\"\""));
-    }
-
-    @Test
-    public void testEmptySingleQuotedNegative() {
-        assertFalse(isSingleQuoted("\"\""));
-    }
-
-    @Test
-    public void testEmptySingleQuotedNegative2() {
-        assertFalse(isSingleQuoted("\""));
-    }
-
-    @Test
-    public void testDoubleQuoted() {
-        assertTrue(isDoubleQuoted("\"\"c:\\program files\\test\\\"\""));
-    }
-
-    @Test
-    public void testEmptyDoubleQuotedNegative() {
-        assertFalse(isDoubleQuoted("\"\"\"\""));
-    }
-
     @Test
     public void testWhiteSpaceSeparatedArgs() {
         List<String> args = splitToWhiteSpaceSeparatedTokens("arg0 arg1 arg2");
@@ -102,7 +52,7 @@ public class ExecParseUtilsTest {
     @Test
     public void testWhitespaceSeparatedArgsWithSpaces() {
         List<String> args = splitToWhiteSpaceSeparatedTokens("\"arg 0 \"   arg1 \"arg 2\"");
-        assertEquals("arg 0 ", args.get(0));
+        assertEquals("arg 0", args.get(0));
         assertEquals("arg1", args.get(1));
         assertEquals("arg 2", args.get(2));
     }
@@ -115,27 +65,25 @@ public class ExecParseUtilsTest {
 
     @Test
     public void testDoubleQuoteAndSpace() {
-        List<String> args = splitToWhiteSpaceSeparatedTokens("\"\"arg0\"\" arg1");
+        List<String> args = splitToWhiteSpaceSeparatedTokens("'\"arg0\"' arg1");
         assertEquals("\"arg0\"", args.get(0));
         assertEquals("arg1", args.get(1));
     }
 
     @Test
     public void testTwoDoubleQuotes() {
-        List<String> args = splitToWhiteSpaceSeparatedTokens("\"\"arg0\"\" \"\"arg1\"\"");
+        List<String> args = splitToWhiteSpaceSeparatedTokens("'\"arg0\"' '\"arg1\"'");
         assertEquals("\"arg0\"", args.get(0));
         assertEquals("\"arg1\"", args.get(1));
     }
 
     @Test
-    public void testWhiteSpaceSeparatedArgsNotClosed() {
-        assertThrows(IllegalArgumentException.class,
-                () -> splitToWhiteSpaceSeparatedTokens("arg 0 \" arg1 \"arg 2\""));
+    public void testRuby() {
+        List<String> args = splitToWhiteSpaceSeparatedTokens("ruby -e 'puts \"Hello, world!\"'");
+        assertEquals(3, args.size());
+        assertEquals("ruby", args.get(0));
+        assertEquals("-e", args.get(1));
+        assertEquals("puts \"Hello, world!\"", args.get(2));
     }
 
-    @Test
-    public void testInvalidQuotes() {
-        assertThrows(IllegalArgumentException.class,
-                () -> splitToWhiteSpaceSeparatedTokens("\"\"arg 0 \" arg1 \"arg 2\""));
-    }
 }