vlsi commented on code in PR #6773:
URL: https://github.com/apache/jmeter/pull/6773#discussion_r4098245426


##########
src/protocol/http/src/main/java/org/apache/jmeter/protocol/http/curl/BasicCurlParser.java:
##########
@@ -829,50 +829,79 @@ public static String[] translateCommandline(String 
toProcess) {
             //no command? no string
             return new String[0];
         }
-        // parse with a simple finite state machine
+        // parse with a character-level finite state machine so that
+        // backslash-escaped quotes inside a quoted token are handled correctly
+        // (e.g. 'tes\'t' or "tes\"t").
 
         final int normal = 0;
         final int inQuote = 1;
         final int inDoubleQuote = 2;
         int state = normal;
-        final StringTokenizer tok = new StringTokenizer(toProcess, "\"\' ", 
true);
         final ArrayList<String> result = new ArrayList<>();
         final StringBuilder current = new StringBuilder();
         boolean lastTokenHasBeenQuoted = false;
 
-        while (tok.hasMoreTokens()) {
-            String nextTok = tok.nextToken();
+        int i = 0;
+        final int len = toProcess.length();
+        while (i < len) {
+            char c = toProcess.charAt(i);
             switch (state) {
                 case inQuote -> {
-                    if ("'".equals(nextTok)) {
+                    if (c == '\\' && i + 1 < len && toProcess.charAt(i + 1) == 
'\'') {
+                        // escaped single-quote inside single-quoted string
+                        current.append('\'');
+                        i += 2;
+                    } else if (c == '\'') {
                         lastTokenHasBeenQuoted = true;
                         state = normal;
+                        i++;
                     } else {
-                        current.append(nextTok);
+                        current.append(c);
+                        i++;
                     }
                 }
                 case inDoubleQuote -> {
-                    if ("\"".equals(nextTok)) {
+                    if (c == '\\' && i + 1 < len && toProcess.charAt(i + 1) == 
'"') {

Review Comment:
   Inside double quotes, the shell treats a backslash as an escape before `"`, 
`\`, `$`, `` ` `` and a newline, and keeps it as a literal character before 
anything else. Handling only `\"` makes a string that ends in an escaped 
backslash impossible to close: `-d "C:\\dir\\" -H "X: y"` parsed on `master` 
and now throws `unbalanced quotes`. `"a\\b"` still yields `a\\b` instead of 
`a\b`. Please implement the full POSIX set for double quotes.



##########
src/protocol/http/src/main/java/org/apache/jmeter/protocol/http/curl/BasicCurlParser.java:
##########
@@ -829,50 +829,79 @@ public static String[] translateCommandline(String 
toProcess) {
             //no command? no string
             return new String[0];
         }
-        // parse with a simple finite state machine
+        // parse with a character-level finite state machine so that
+        // backslash-escaped quotes inside a quoted token are handled correctly
+        // (e.g. 'tes\'t' or "tes\"t").
 
         final int normal = 0;
         final int inQuote = 1;
         final int inDoubleQuote = 2;
         int state = normal;
-        final StringTokenizer tok = new StringTokenizer(toProcess, "\"\' ", 
true);
         final ArrayList<String> result = new ArrayList<>();
         final StringBuilder current = new StringBuilder();
         boolean lastTokenHasBeenQuoted = false;
 
-        while (tok.hasMoreTokens()) {
-            String nextTok = tok.nextToken();
+        int i = 0;
+        final int len = toProcess.length();
+        while (i < len) {
+            char c = toProcess.charAt(i);
             switch (state) {
                 case inQuote -> {
-                    if ("'".equals(nextTok)) {
+                    if (c == '\\' && i + 1 < len && toProcess.charAt(i + 1) == 
'\'') {

Review Comment:
   In a POSIX shell, a backslash inside single quotes is a literal character: 
nothing can escape the closing `'`. This branch therefore breaks valid 
commands. `curl -d 'C:\dir\' -H 'X: y' http://x` passes `C:\dir\` in bash and 
on `master`, and now throws `unbalanced quotes`, because the `\'` swallows the 
closing quote. The same happens to any regex or JSON value that ends in a 
backslash.
   
   `'tes\'t'` from #6374 is not a valid shell word either: bash reports 
`unexpected EOF while looking for matching '`. Shells and browsers write a 
single quote inside single quotes as `'tes'\''t'` or as `$'tes\'t'`, and this 
PR supports neither form. Please drop this branch and follow the POSIX rule; 
`'tes'\''t'` will then parse through the existing states.



##########
src/protocol/http/src/main/java/org/apache/jmeter/protocol/http/curl/BasicCurlParser.java:
##########
@@ -829,50 +829,79 @@ public static String[] translateCommandline(String 
toProcess) {
             //no command? no string
             return new String[0];
         }
-        // parse with a simple finite state machine
+        // parse with a character-level finite state machine so that

Review Comment:
   This comment describes the change (what is now handled "correctly") and uses 
`'tes\'t'`, which is not valid shell syntax, as its example. Please describe 
the supported quoting rules in the method's Javadoc and remove this comment. 
The comments `// escaped single-quote inside single-quoted string`, `// escaped 
double-quote inside double-quoted string` and `// also skip a following \n if 
we consumed \r` only repeat the next line of code and can be removed as well.



##########
src/protocol/http/src/test/java/org/apache/jmeter/curl/BasicCurlParserTest.java:
##########
@@ -770,4 +770,126 @@ public void testIsValidCookie() {
         assertTrue(BasicCurlParser.isValidCookie("a=b;c=d"), "The string 
should be cookies");
         assertFalse(BasicCurlParser.isValidCookie("test.txt"), "A filename is 
not a valid cookie");
     }
+
+    /**
+     * Escaped single-quote inside a single-quoted --data value must not cause
+     * "unbalanced quotes" and must be included literally in the post data.
+     * Reproduces https://github.com/apache/jmeter/issues/6374
+     */
+    @Test
+    public void testEscapedSingleQuoteInData() {

Review Comment:
   This test makes `'tes\'t'` (an unterminated quote in bash) a supported 
input, so it pins behavior that a POSIX-compliant parser has to reject. The 
same applies to `testTranslateCommandlineEscapedSingleQuoteInsideSingleQuotes` 
and `testTranslateCommandlineMultipleEscapedQuotes`. Please replace them with 
`'tes'\''t'` and add the regression cases listed in the review summary.



##########
src/protocol/http/src/test/java/org/apache/jmeter/curl/BasicCurlParserTest.java:
##########
@@ -770,4 +770,126 @@ public void testIsValidCookie() {
         assertTrue(BasicCurlParser.isValidCookie("a=b;c=d"), "The string 
should be cookies");
         assertFalse(BasicCurlParser.isValidCookie("test.txt"), "A filename is 
not a valid cookie");
     }
+
+    /**
+     * Escaped single-quote inside a single-quoted --data value must not cause
+     * "unbalanced quotes" and must be included literally in the post data.
+     * Reproduces https://github.com/apache/jmeter/issues/6374
+     */
+    @Test
+    public void testEscapedSingleQuoteInData() {
+        // Shell representation: --data 'tes\'t'
+        // In Java string: the outer single-quotes are literal chars, the \' 
is a backslash + single-quote
+        String curl = " curl -X POST \"localhost.com\" --data 'tes\\'t'";
+        BasicCurlParser basicCurlParser = new BasicCurlParser();
+        BasicCurlParser.Request request = basicCurlParser.parse(curl);
+        assertEquals("tes't", request.getPostData(),
+                "Escaped single-quote inside single-quoted data should be 
preserved");
+    }
+
+    /**
+     * Escaped double-quote inside a double-quoted --data value must not cause
+     * "unbalanced quotes" and must be included literally in the post data.
+     * Reproduces https://github.com/apache/jmeter/issues/6374
+     */
+    @Test
+    public void testEscapedDoubleQuoteInData() {
+        // Shell representation: --data "tes\"t"
+        String curl = " curl -X POST \"localhost.com\" --data \"tes\\\"t\"";
+        BasicCurlParser basicCurlParser = new BasicCurlParser();
+        BasicCurlParser.Request request = basicCurlParser.parse(curl);
+        assertEquals("tes\"t", request.getPostData(),
+                "Escaped double-quote inside double-quoted data should be 
preserved");
+    }
+
+    // -----------------------------------------------------------------------
+    // Direct unit tests for translateCommandline (tokenizer-level coverage)
+    // -----------------------------------------------------------------------
+
+    /** Plain unquoted tokens are split on spaces. */
+    @Test
+    public void testTranslateCommandlineSimpleTokens() {
+        String[] result = BasicCurlParser.translateCommandline("curl -X POST 
http://example.com";);
+        assertEquals(4, result.length);
+        assertEquals("curl", result[0]);
+        assertEquals("-X", result[1]);
+        assertEquals("POST", result[2]);
+        assertEquals("http://example.com";, result[3]);
+    }
+
+    /** Single-quoted token: quotes are stripped, content preserved verbatim. 
*/
+    @Test
+    public void testTranslateCommandlineSingleQuotedToken() {
+        String[] result = BasicCurlParser.translateCommandline("curl 'hello 
world'");
+        assertEquals(2, result.length);
+        assertEquals("curl", result[0]);
+        assertEquals("hello world", result[1]);
+    }
+
+    /** Double-quoted token: quotes are stripped, content preserved verbatim. 
*/
+    @Test
+    public void testTranslateCommandlineDoubleQuotedToken() {
+        String[] result = BasicCurlParser.translateCommandline("curl \"hello 
world\"");
+        assertEquals(2, result.length);
+        assertEquals("curl", result[0]);
+        assertEquals("hello world", result[1]);
+    }
+
+    /**
+     * Backslash-escaped single-quote inside a single-quoted token must be
+     * treated as a literal single-quote (fix for issue #6374).
+     */
+    @Test
+    public void testTranslateCommandlineEscapedSingleQuoteInsideSingleQuotes() 
{
+        // Input string (as seen by the JVM): 'tes\'t'
+        // i.e. single-quote, t, e, s, backslash, single-quote, t, single-quote
+        String[] result = BasicCurlParser.translateCommandline("'tes\\'t'");
+        assertEquals(1, result.length);
+        assertEquals("tes't", result[0]);
+    }
+
+    /**
+     * Backslash-escaped double-quote inside a double-quoted token must be
+     * treated as a literal double-quote (fix for issue #6374).
+     */
+    @Test
+    public void testTranslateCommandlineEscapedDoubleQuoteInsideDoubleQuotes() 
{
+        // Input string (as seen by the JVM): "tes\"t"
+        String[] result = BasicCurlParser.translateCommandline("\"tes\\\"t\"");
+        assertEquals(1, result.length);
+        assertEquals("tes\"t", result[0]);
+    }
+
+    /** Multiple escaped quotes in a single token are all preserved. */
+    @Test
+    public void testTranslateCommandlineMultipleEscapedQuotes() {
+        // 'it\'s a test\'s value'  →  it's a test's value
+        String[] result = BasicCurlParser.translateCommandline("'it\\'s a 
test\\'s value'");
+        assertEquals(1, result.length);
+        assertEquals("it's a test's value", result[0]);
+    }
+
+    /** Backslash + newline (line continuation) outside quotes is consumed 
silently. */
+    @Test
+    public void testTranslateCommandlineBackslashLineContinuation() {
+        String[] result = BasicCurlParser.translateCommandline("curl \\\n-d 
'hey'");
+        assertEquals(3, result.length);
+        assertEquals("curl", result[0]);
+        assertEquals("-d", result[1]);
+        assertEquals("hey", result[2]);
+    }
+
+    /** Empty input returns an empty array. */
+    @Test
+    public void testTranslateCommandlineEmptyInput() {
+        assertEquals(0, BasicCurlParser.translateCommandline("").length);
+    }
+
+    /** Genuinely unbalanced quotes still throw IllegalArgumentException. */

Review Comment:
   `Genuinely` adds nothing here or in the assertion message on line 893: 
`Unbalanced quotes throw IllegalArgumentException.` The message should give the 
input (`translateCommandline("curl \"unclosed")`) rather than repeat the test 
name.



##########
src/protocol/http/src/main/java/org/apache/jmeter/protocol/http/curl/BasicCurlParser.java:
##########
@@ -829,50 +829,79 @@ public static String[] translateCommandline(String 
toProcess) {
             //no command? no string
             return new String[0];
         }
-        // parse with a simple finite state machine
+        // parse with a character-level finite state machine so that
+        // backslash-escaped quotes inside a quoted token are handled correctly
+        // (e.g. 'tes\'t' or "tes\"t").
 
         final int normal = 0;
         final int inQuote = 1;
         final int inDoubleQuote = 2;
         int state = normal;
-        final StringTokenizer tok = new StringTokenizer(toProcess, "\"\' ", 
true);
         final ArrayList<String> result = new ArrayList<>();
         final StringBuilder current = new StringBuilder();
         boolean lastTokenHasBeenQuoted = false;
 
-        while (tok.hasMoreTokens()) {
-            String nextTok = tok.nextToken();
+        int i = 0;
+        final int len = toProcess.length();
+        while (i < len) {
+            char c = toProcess.charAt(i);
             switch (state) {
                 case inQuote -> {
-                    if ("'".equals(nextTok)) {
+                    if (c == '\\' && i + 1 < len && toProcess.charAt(i + 1) == 
'\'') {
+                        // escaped single-quote inside single-quoted string
+                        current.append('\'');
+                        i += 2;
+                    } else if (c == '\'') {
                         lastTokenHasBeenQuoted = true;
                         state = normal;
+                        i++;
                     } else {
-                        current.append(nextTok);
+                        current.append(c);
+                        i++;
                     }
                 }
                 case inDoubleQuote -> {
-                    if ("\"".equals(nextTok)) {
+                    if (c == '\\' && i + 1 < len && toProcess.charAt(i + 1) == 
'"') {
+                        // escaped double-quote inside double-quoted string
+                        current.append('"');
+                        i += 2;
+                    } else if (c == '"') {
                         lastTokenHasBeenQuoted = true;
                         state = normal;
+                        i++;
                     } else {
-                        current.append(nextTok);
+                        current.append(c);
+                        i++;
                     }
                 }
                 default -> {
-                    if ("'".equals(nextTok)) {
+                    if (c == '\'') {

Review Comment:
   `$'…'` (ANSI-C quoting) is what Chrome's "Copy as cURL (bash)" emits 
whenever the body contains a single quote or a non-printable character, e.g. 
`--data-raw $'{"name":"O\'Brien"}'`. Before this PR such input failed with 
`unbalanced quotes`. Now it parses without an error, and the `$` becomes part 
of the request body (`$'tes\'t'` gives `$tes't`). Please either support `$'…'` 
or keep rejecting it; sending a corrupted body is worse than an error message.



##########
src/protocol/http/src/main/java/org/apache/jmeter/protocol/http/curl/BasicCurlParser.java:
##########
@@ -829,50 +829,79 @@ public static String[] translateCommandline(String 
toProcess) {
             //no command? no string
             return new String[0];
         }
-        // parse with a simple finite state machine
+        // parse with a character-level finite state machine so that
+        // backslash-escaped quotes inside a quoted token are handled correctly
+        // (e.g. 'tes\'t' or "tes\"t").
 
         final int normal = 0;
         final int inQuote = 1;
         final int inDoubleQuote = 2;
         int state = normal;
-        final StringTokenizer tok = new StringTokenizer(toProcess, "\"\' ", 
true);
         final ArrayList<String> result = new ArrayList<>();
         final StringBuilder current = new StringBuilder();
         boolean lastTokenHasBeenQuoted = false;
 
-        while (tok.hasMoreTokens()) {
-            String nextTok = tok.nextToken();
+        int i = 0;
+        final int len = toProcess.length();
+        while (i < len) {
+            char c = toProcess.charAt(i);
             switch (state) {
                 case inQuote -> {
-                    if ("'".equals(nextTok)) {
+                    if (c == '\\' && i + 1 < len && toProcess.charAt(i + 1) == 
'\'') {
+                        // escaped single-quote inside single-quoted string
+                        current.append('\'');
+                        i += 2;
+                    } else if (c == '\'') {
                         lastTokenHasBeenQuoted = true;
                         state = normal;
+                        i++;
                     } else {
-                        current.append(nextTok);
+                        current.append(c);
+                        i++;
                     }
                 }
                 case inDoubleQuote -> {
-                    if ("\"".equals(nextTok)) {
+                    if (c == '\\' && i + 1 < len && toProcess.charAt(i + 1) == 
'"') {
+                        // escaped double-quote inside double-quoted string
+                        current.append('"');
+                        i += 2;
+                    } else if (c == '"') {
                         lastTokenHasBeenQuoted = true;
                         state = normal;
+                        i++;
                     } else {
-                        current.append(nextTok);
+                        current.append(c);
+                        i++;
                     }
                 }
                 default -> {
-                    if ("'".equals(nextTok)) {
+                    if (c == '\'') {
                         state = inQuote;
-                    } else if ("\"".equals(nextTok)) {
+                        i++;
+                    } else if (c == '"') {
                         state = inDoubleQuote;
-                    } else if (" ".equals(nextTok)) {
+                        i++;
+                    } else if (c == ' ') {
                         if (lastTokenHasBeenQuoted || !current.isEmpty()) {
                             result.add(current.toString());
                             current.setLength(0);
                         }
+                        lastTokenHasBeenQuoted = false;
+                        i++;
+                    } else if (c == '\\' && i + 1 < len

Review Comment:
   Outside quotes, a POSIX shell treats a backslash as an escape for any 
character, not only for a line break: `tes\'t` is `tes't`. With this change 
`tes\'t` still opens a quote and throws.
   
   This branch also changes how `\` followed by CRLF is handled: `master` 
produced an extra argument `"\n"`, and this code drops it. Please add a test 
for CRLF and mention the change in the PR description.



##########
src/protocol/http/src/test/java/org/apache/jmeter/curl/BasicCurlParserTest.java:
##########
@@ -770,4 +770,126 @@ public void testIsValidCookie() {
         assertTrue(BasicCurlParser.isValidCookie("a=b;c=d"), "The string 
should be cookies");
         assertFalse(BasicCurlParser.isValidCookie("test.txt"), "A filename is 
not a valid cookie");
     }
+
+    /**
+     * Escaped single-quote inside a single-quoted --data value must not cause
+     * "unbalanced quotes" and must be included literally in the post data.
+     * Reproduces https://github.com/apache/jmeter/issues/6374
+     */
+    @Test
+    public void testEscapedSingleQuoteInData() {
+        // Shell representation: --data 'tes\'t'
+        // In Java string: the outer single-quotes are literal chars, the \' 
is a backslash + single-quote
+        String curl = " curl -X POST \"localhost.com\" --data 'tes\\'t'";
+        BasicCurlParser basicCurlParser = new BasicCurlParser();
+        BasicCurlParser.Request request = basicCurlParser.parse(curl);
+        assertEquals("tes't", request.getPostData(),
+                "Escaped single-quote inside single-quoted data should be 
preserved");
+    }
+
+    /**
+     * Escaped double-quote inside a double-quoted --data value must not cause
+     * "unbalanced quotes" and must be included literally in the post data.
+     * Reproduces https://github.com/apache/jmeter/issues/6374
+     */
+    @Test
+    public void testEscapedDoubleQuoteInData() {
+        // Shell representation: --data "tes\"t"
+        String curl = " curl -X POST \"localhost.com\" --data \"tes\\\"t\"";
+        BasicCurlParser basicCurlParser = new BasicCurlParser();
+        BasicCurlParser.Request request = basicCurlParser.parse(curl);
+        assertEquals("tes\"t", request.getPostData(),
+                "Escaped double-quote inside double-quoted data should be 
preserved");
+    }
+
+    // -----------------------------------------------------------------------
+    // Direct unit tests for translateCommandline (tokenizer-level coverage)

Review Comment:
   Please remove the banner comment. The tokenizer cases differ only in the 
input and the expected tokens, so they fit one `@ParameterizedTest` with a name 
per case (for example `@MethodSource` with `Arguments.of("backslash before 
closing single quote", "-d 'C:\\dir\\'", new String[]{"-d", "C:\\dir\\"})`). 
The expected tokens for each case should come from bash.



##########
.github/workflows/gradle-wrapper-validation.yml:
##########
@@ -7,4 +7,4 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v6
-      - uses: 
gradle/actions/wrapper-validation@0723195856401067f7a2779048b490ace7a47d7c # 
v5.0.2
+      - uses: 
gradle/actions/wrapper-validation@3f131e8634966bd73d06cc69884922b02e6faf92 # 
v6.2.0

Review Comment:
   This change is unrelated to #6374; please move it to its own PR. In the ASF 
allowlist ([`apache/infrastructure-actions` 
`actions.yml`](https://github.com/apache/infrastructure-actions/blob/main/actions.yml)),
 `wrapper-validation@3f131e8…` (v6.2.0) has `expires_at: 2026-10-30`, so the 
workflow will fail again in five weeks. v6.3.0 
(`9c971963bec38e04b3d30dcc455b5382be2fdbfb`) has no expiry date.



##########
src/protocol/http/src/test/java/org/apache/jmeter/curl/BasicCurlParserTest.java:
##########
@@ -770,4 +770,126 @@ public void testIsValidCookie() {
         assertTrue(BasicCurlParser.isValidCookie("a=b;c=d"), "The string 
should be cookies");
         assertFalse(BasicCurlParser.isValidCookie("test.txt"), "A filename is 
not a valid cookie");
     }
+
+    /**
+     * Escaped single-quote inside a single-quoted --data value must not cause
+     * "unbalanced quotes" and must be included literally in the post data.
+     * Reproduces https://github.com/apache/jmeter/issues/6374
+     */
+    @Test
+    public void testEscapedSingleQuoteInData() {
+        // Shell representation: --data 'tes\'t'
+        // In Java string: the outer single-quotes are literal chars, the \' 
is a backslash + single-quote
+        String curl = " curl -X POST \"localhost.com\" --data 'tes\\'t'";
+        BasicCurlParser basicCurlParser = new BasicCurlParser();
+        BasicCurlParser.Request request = basicCurlParser.parse(curl);
+        assertEquals("tes't", request.getPostData(),
+                "Escaped single-quote inside single-quoted data should be 
preserved");
+    }
+
+    /**
+     * Escaped double-quote inside a double-quoted --data value must not cause
+     * "unbalanced quotes" and must be included literally in the post data.
+     * Reproduces https://github.com/apache/jmeter/issues/6374
+     */
+    @Test
+    public void testEscapedDoubleQuoteInData() {
+        // Shell representation: --data "tes\"t"
+        String curl = " curl -X POST \"localhost.com\" --data \"tes\\\"t\"";
+        BasicCurlParser basicCurlParser = new BasicCurlParser();
+        BasicCurlParser.Request request = basicCurlParser.parse(curl);
+        assertEquals("tes\"t", request.getPostData(),
+                "Escaped double-quote inside double-quoted data should be 
preserved");
+    }
+
+    // -----------------------------------------------------------------------
+    // Direct unit tests for translateCommandline (tokenizer-level coverage)
+    // -----------------------------------------------------------------------
+
+    /** Plain unquoted tokens are split on spaces. */
+    @Test
+    public void testTranslateCommandlineSimpleTokens() {
+        String[] result = BasicCurlParser.translateCommandline("curl -X POST 
http://example.com";);
+        assertEquals(4, result.length);
+        assertEquals("curl", result[0]);
+        assertEquals("-X", result[1]);
+        assertEquals("POST", result[2]);
+        assertEquals("http://example.com";, result[3]);
+    }
+
+    /** Single-quoted token: quotes are stripped, content preserved verbatim. 
*/
+    @Test
+    public void testTranslateCommandlineSingleQuotedToken() {
+        String[] result = BasicCurlParser.translateCommandline("curl 'hello 
world'");
+        assertEquals(2, result.length);
+        assertEquals("curl", result[0]);
+        assertEquals("hello world", result[1]);
+    }
+
+    /** Double-quoted token: quotes are stripped, content preserved verbatim. 
*/
+    @Test
+    public void testTranslateCommandlineDoubleQuotedToken() {
+        String[] result = BasicCurlParser.translateCommandline("curl \"hello 
world\"");
+        assertEquals(2, result.length);
+        assertEquals("curl", result[0]);
+        assertEquals("hello world", result[1]);
+    }
+
+    /**
+     * Backslash-escaped single-quote inside a single-quoted token must be
+     * treated as a literal single-quote (fix for issue #6374).
+     */
+    @Test
+    public void testTranslateCommandlineEscapedSingleQuoteInsideSingleQuotes() 
{
+        // Input string (as seen by the JVM): 'tes\'t'
+        // i.e. single-quote, t, e, s, backslash, single-quote, t, single-quote
+        String[] result = BasicCurlParser.translateCommandline("'tes\\'t'");
+        assertEquals(1, result.length);
+        assertEquals("tes't", result[0]);
+    }
+
+    /**
+     * Backslash-escaped double-quote inside a double-quoted token must be
+     * treated as a literal double-quote (fix for issue #6374).
+     */
+    @Test
+    public void testTranslateCommandlineEscapedDoubleQuoteInsideDoubleQuotes() 
{
+        // Input string (as seen by the JVM): "tes\"t"
+        String[] result = BasicCurlParser.translateCommandline("\"tes\\\"t\"");
+        assertEquals(1, result.length);
+        assertEquals("tes\"t", result[0]);
+    }
+
+    /** Multiple escaped quotes in a single token are all preserved. */
+    @Test
+    public void testTranslateCommandlineMultipleEscapedQuotes() {
+        // 'it\'s a test\'s value'  →  it's a test's value
+        String[] result = BasicCurlParser.translateCommandline("'it\\'s a 
test\\'s value'");
+        assertEquals(1, result.length);
+        assertEquals("it's a test's value", result[0]);
+    }
+
+    /** Backslash + newline (line continuation) outside quotes is consumed 
silently. */
+    @Test
+    public void testTranslateCommandlineBackslashLineContinuation() {

Review Comment:
   This duplicates the existing `testBackslashAtLineEnding` (`"curl \\\n-d 
'hey' …"`). The case this PR changes is `\` followed by `\r\n`, which has no 
test.



##########
src/protocol/http/src/test/java/org/apache/jmeter/curl/BasicCurlParserTest.java:
##########
@@ -770,4 +770,126 @@ public void testIsValidCookie() {
         assertTrue(BasicCurlParser.isValidCookie("a=b;c=d"), "The string 
should be cookies");
         assertFalse(BasicCurlParser.isValidCookie("test.txt"), "A filename is 
not a valid cookie");
     }
+
+    /**
+     * Escaped single-quote inside a single-quoted --data value must not cause
+     * "unbalanced quotes" and must be included literally in the post data.
+     * Reproduces https://github.com/apache/jmeter/issues/6374
+     */
+    @Test
+    public void testEscapedSingleQuoteInData() {
+        // Shell representation: --data 'tes\'t'
+        // In Java string: the outer single-quotes are literal chars, the \' 
is a backslash + single-quote
+        String curl = " curl -X POST \"localhost.com\" --data 'tes\\'t'";
+        BasicCurlParser basicCurlParser = new BasicCurlParser();
+        BasicCurlParser.Request request = basicCurlParser.parse(curl);
+        assertEquals("tes't", request.getPostData(),
+                "Escaped single-quote inside single-quoted data should be 
preserved");
+    }
+
+    /**
+     * Escaped double-quote inside a double-quoted --data value must not cause
+     * "unbalanced quotes" and must be included literally in the post data.
+     * Reproduces https://github.com/apache/jmeter/issues/6374
+     */
+    @Test
+    public void testEscapedDoubleQuoteInData() {
+        // Shell representation: --data "tes\"t"
+        String curl = " curl -X POST \"localhost.com\" --data \"tes\\\"t\"";
+        BasicCurlParser basicCurlParser = new BasicCurlParser();
+        BasicCurlParser.Request request = basicCurlParser.parse(curl);
+        assertEquals("tes\"t", request.getPostData(),
+                "Escaped double-quote inside double-quoted data should be 
preserved");
+    }
+
+    // -----------------------------------------------------------------------
+    // Direct unit tests for translateCommandline (tokenizer-level coverage)
+    // -----------------------------------------------------------------------
+
+    /** Plain unquoted tokens are split on spaces. */
+    @Test
+    public void testTranslateCommandlineSimpleTokens() {
+        String[] result = BasicCurlParser.translateCommandline("curl -X POST 
http://example.com";);
+        assertEquals(4, result.length);

Review Comment:
   `assertEquals(4, result.length)` followed by per-element `assertEquals` 
stops at the first mismatch and never prints the actual tokens. 
`assertArrayEquals(new String[]{"curl", "-X", "POST", "http://example.com"}, 
result)` prints both arrays when it fails. The same pattern appears in every 
`testTranslateCommandline*` test.



##########
src/protocol/http/src/test/java/org/apache/jmeter/curl/BasicCurlParserTest.java:
##########
@@ -770,4 +770,126 @@ public void testIsValidCookie() {
         assertTrue(BasicCurlParser.isValidCookie("a=b;c=d"), "The string 
should be cookies");
         assertFalse(BasicCurlParser.isValidCookie("test.txt"), "A filename is 
not a valid cookie");
     }
+
+    /**
+     * Escaped single-quote inside a single-quoted --data value must not cause
+     * "unbalanced quotes" and must be included literally in the post data.
+     * Reproduces https://github.com/apache/jmeter/issues/6374
+     */
+    @Test
+    public void testEscapedSingleQuoteInData() {
+        // Shell representation: --data 'tes\'t'
+        // In Java string: the outer single-quotes are literal chars, the \' 
is a backslash + single-quote
+        String curl = " curl -X POST \"localhost.com\" --data 'tes\\'t'";
+        BasicCurlParser basicCurlParser = new BasicCurlParser();
+        BasicCurlParser.Request request = basicCurlParser.parse(curl);
+        assertEquals("tes't", request.getPostData(),
+                "Escaped single-quote inside single-quoted data should be 
preserved");
+    }
+
+    /**
+     * Escaped double-quote inside a double-quoted --data value must not cause
+     * "unbalanced quotes" and must be included literally in the post data.
+     * Reproduces https://github.com/apache/jmeter/issues/6374
+     */
+    @Test
+    public void testEscapedDoubleQuoteInData() {
+        // Shell representation: --data "tes\"t"
+        String curl = " curl -X POST \"localhost.com\" --data \"tes\\\"t\"";
+        BasicCurlParser basicCurlParser = new BasicCurlParser();
+        BasicCurlParser.Request request = basicCurlParser.parse(curl);
+        assertEquals("tes\"t", request.getPostData(),
+                "Escaped double-quote inside double-quoted data should be 
preserved");
+    }
+
+    // -----------------------------------------------------------------------
+    // Direct unit tests for translateCommandline (tokenizer-level coverage)
+    // -----------------------------------------------------------------------
+
+    /** Plain unquoted tokens are split on spaces. */
+    @Test
+    public void testTranslateCommandlineSimpleTokens() {
+        String[] result = BasicCurlParser.translateCommandline("curl -X POST 
http://example.com";);
+        assertEquals(4, result.length);
+        assertEquals("curl", result[0]);
+        assertEquals("-X", result[1]);
+        assertEquals("POST", result[2]);
+        assertEquals("http://example.com";, result[3]);
+    }
+
+    /** Single-quoted token: quotes are stripped, content preserved verbatim. 
*/
+    @Test
+    public void testTranslateCommandlineSingleQuotedToken() {
+        String[] result = BasicCurlParser.translateCommandline("curl 'hello 
world'");
+        assertEquals(2, result.length);
+        assertEquals("curl", result[0]);
+        assertEquals("hello world", result[1]);
+    }
+
+    /** Double-quoted token: quotes are stripped, content preserved verbatim. 
*/
+    @Test
+    public void testTranslateCommandlineDoubleQuotedToken() {
+        String[] result = BasicCurlParser.translateCommandline("curl \"hello 
world\"");
+        assertEquals(2, result.length);
+        assertEquals("curl", result[0]);
+        assertEquals("hello world", result[1]);
+    }
+
+    /**
+     * Backslash-escaped single-quote inside a single-quoted token must be
+     * treated as a literal single-quote (fix for issue #6374).

Review Comment:
   `(fix for issue #6374)` gives the issue number instead of the defect. Please 
state the rule the test checks and, if needed, the old failure in one sentence 
(`used to throw IllegalArgumentException: unbalanced quotes`), with the issue 
number after it. The same applies to line 853.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to