This is an automated email from the ASF dual-hosted git repository.
fschumacher pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/jmeter.git
The following commit(s) were added to refs/heads/master by this push:
new f045cf5 Sending mime type with parameter throws
IllegalArgumentException
f045cf5 is described below
commit f045cf5e1604c68b7d43986fe9bd82a102fa2b76
Author: Felix Schumacher <[email protected]>
AuthorDate: Wed Dec 23 10:45:44 2020 +0100
Sending mime type with parameter throws IllegalArgumentException
More stuff from that bugzilla entry:
* Better distinguishing between a quoted filename and a quoted name, that
contains an @ char
* Allow more than one header and parameter with the same name to be added
* Simplify the code in ParseCurlCommandAction by moving some of the logic
in extra classes
What is still missing are curl specialities like
--form file=@"file with; semicolon or space";type=text/something
--form param="red green blue";headers="X-Something: \"yeah; something\""
Bugzilla Id: 65024
---
src/protocol/build.gradle.kts | 8 +++
.../jmeter/protocol/http/curl/ArgumentHolder.java | 55 +++++++++++++++
.../jmeter/protocol/http/curl/BasicCurlParser.java | 51 +++++++++-----
.../protocol/http/curl/FileArgumentHolder.java | 80 ++++++++++++++++++++++
.../protocol/http/curl/StringArgumentHolder.java | 74 ++++++++++++++++++++
.../http/gui/action/ParseCurlCommandAction.java | 57 +++++++--------
.../apache/jmeter/curl/BasicCurlParserTest.java | 72 ++++++++++++++-----
7 files changed, 334 insertions(+), 63 deletions(-)
diff --git a/src/protocol/build.gradle.kts b/src/protocol/build.gradle.kts
index d0855cf..263eec8 100644
--- a/src/protocol/build.gradle.kts
+++ b/src/protocol/build.gradle.kts
@@ -89,6 +89,14 @@ project("http") {
implementation("com.fasterxml.jackson.core:jackson-databind")
testImplementation(testFixtures(project(":src:testkit-wiremock")))
testImplementation("com.github.tomakehurst:wiremock-jre8")
+ // For some reason JMeter bundles just tika-core and tika-parsers
without transitive
+ // dependencies. So we exclude those
+ implementation("org.apache.tika:tika-core") {
+ isTransitive = false
+ }
+ runtimeOnly("org.apache.tika:tika-parsers") {
+ isTransitive = false
+ }
}
}
diff --git
a/src/protocol/http/src/main/java/org/apache/jmeter/protocol/http/curl/ArgumentHolder.java
b/src/protocol/http/src/main/java/org/apache/jmeter/protocol/http/curl/ArgumentHolder.java
new file mode 100644
index 0000000..ea9294a
--- /dev/null
+++
b/src/protocol/http/src/main/java/org/apache/jmeter/protocol/http/curl/ArgumentHolder.java
@@ -0,0 +1,55 @@
+/*
+ * 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.jmeter.protocol.http.curl;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+import org.apache.commons.lang3.tuple.Pair;
+
+public interface ArgumentHolder {
+
+ String getName();
+
+ Map<String, String> getMetadata();
+
+ default String getContentType() {
+ return getMetadata().get("type");
+ }
+
+ default boolean hasContenType() {
+ return getMetadata().containsKey("type");
+ }
+
+ static Pair<String, Map<String, String>> parse(String name) {
+ if (name.contains(";")) {
+ String[] parts = name.split(";");
+ String realName = parts[0];
+ Map<String, String> metadata = new HashMap<>();
+ for (int i = 1; i< parts.length; i++) {
+ String[] typeParts = parts[i].split("\\s*=\\s*", 2);
+ metadata.put(typeParts[0].toLowerCase(Locale.US),
typeParts[1]);
+ }
+ return Pair.of(realName, metadata);
+ } else {
+ return Pair.of(name, Collections.emptyMap());
+ }
+ }
+}
diff --git
a/src/protocol/http/src/main/java/org/apache/jmeter/protocol/http/curl/BasicCurlParser.java
b/src/protocol/http/src/main/java/org/apache/jmeter/protocol/http/curl/BasicCurlParser.java
index 9471130..4fb6581 100644
---
a/src/protocol/http/src/main/java/org/apache/jmeter/protocol/http/curl/BasicCurlParser.java
+++
b/src/protocol/http/src/main/java/org/apache/jmeter/protocol/http/curl/BasicCurlParser.java
@@ -32,6 +32,7 @@ import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
+import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
@@ -43,6 +44,8 @@ import org.apache.commons.cli.avalon.CLArgsParser;
import org.apache.commons.cli.avalon.CLOption;
import org.apache.commons.cli.avalon.CLOptionDescriptor;
import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.tuple.Pair;
import org.apache.jmeter.protocol.http.control.AuthManager.Mechanism;
import org.apache.jmeter.protocol.http.control.Authorization;
import org.apache.jmeter.protocol.http.control.Cookie;
@@ -123,7 +126,7 @@ public class BasicCurlParser {
public static final class Request {
private boolean compressed;
private String url;
- private Map<String, String> headers = new LinkedHashMap<>();
+ private List<Pair<String, String>> headers = new ArrayList<>();
private String method = "GET";
private String postData;
private String interfaceName;
@@ -133,8 +136,8 @@ public class BasicCurlParser {
private String filepathCookie="";
private Authorization authorization = new Authorization();
private String caCert = "";
- private Map<String, String> formData = new LinkedHashMap<>();
- private Map<String, String> formStringData = new LinkedHashMap<>();
+ private List<Pair<String, ArgumentHolder>> formData = new
ArrayList<>();
+ private List<Pair<String, String>> formStringData = new ArrayList<>();
private Set<String> dnsServers = new HashSet<>();
private boolean isKeepAlive = true;
private double maxTime = -1;
@@ -146,6 +149,7 @@ public class BasicCurlParser {
private int limitRate = 0;
private String noproxy;
private static final List<String> HEADERS_TO_IGNORE =
Arrays.asList("Connection", "Host");// $NON-NLS-1$
+ private static final List<String> UNIQUE_HEADERS =
Arrays.asList("user-agent"); // $NON-NLS-1$
private static final int ONE_KILOBYTE_IN_CPS = 1024;
public Request() {
super();
@@ -169,7 +173,11 @@ public class BasicCurlParser {
* @param value the post data
*/
public void setPostData(String value) {
- this.postData = value;
+ if (StringUtils.isBlank(this.postData)) {
+ this.postData = value;
+ } else {
+ this.postData = this.postData + "&" + value;
+ }
}
/**
@@ -200,8 +208,13 @@ public class BasicCurlParser {
public void addHeader(String name, String value) {
if ("COOKIE".equalsIgnoreCase(name)) {
this.cookieInHeaders = value;
- } else if (!HEADERS_TO_IGNORE.contains(name)) {
- headers.put(name, value);
+ } else if (HEADERS_TO_IGNORE.contains(name)) {
+ return;
+ } else {
+ if (UNIQUE_HEADERS.contains(name.toLowerCase(Locale.US))) {
+ headers.removeIf(p -> p.getLeft().equalsIgnoreCase(name));
+ }
+ headers.add(Pair.of(name, value));
}
}
@@ -239,8 +252,8 @@ public class BasicCurlParser {
/**
* @return the headers
*/
- public Map<String, String> getHeaders() {
- return Collections.unmodifiableMap(this.headers);
+ public List<Pair<String, String>> getHeaders() {
+ return Collections.unmodifiableList(this.headers);
}
/**
@@ -406,8 +419,8 @@ public class BasicCurlParser {
/**
* @return the map of form data
*/
- public Map<String, String> getFormStringData() {
- return Collections.unmodifiableMap(this.formStringData);
+ public List<Pair<String,String>> getFormStringData() {
+ return Collections.unmodifiableList(this.formStringData);
}
/**
@@ -415,22 +428,22 @@ public class BasicCurlParser {
* @param value the value of form data
*/
public void addFormStringData(String key, String value) {
- formStringData.put(key, value);
+ formStringData.add(Pair.of(key, value));
}
/**
* @return the map of form data
*/
- public Map<String, String> getFormData() {
- return Collections.unmodifiableMap(this.formData);
+ public List<Pair<String,ArgumentHolder>> getFormData() {
+ return Collections.unmodifiableList(this.formData);
}
/**
* @param key the key of form data
* @param value the value of form data
*/
- public void addFormData(String key, String value) {
- formData.put(key, value);
+ public void addFormData(String key, ArgumentHolder value) {
+ formData.add(Pair.of(key, value));
}
/**
@@ -541,7 +554,7 @@ public class BasicCurlParser {
new CLOptionDescriptor("request",
CLOptionDescriptor.ARGUMENT_REQUIRED, METHOD_OPT,
"Pass custom header LINE to server");
private static final CLOptionDescriptor D_DATA_OPT =
- new CLOptionDescriptor("data",
CLOptionDescriptor.ARGUMENT_REQUIRED, DATA_OPT,
+ new CLOptionDescriptor("data",
CLOptionDescriptor.ARGUMENT_REQUIRED | CLOptionDescriptor.DUPLICATES_ALLOWED,
DATA_OPT,
"HTTP POST data");
private static final CLOptionDescriptor D_DATA_ASCII_OPT = new
CLOptionDescriptor("data-ascii",
CLOptionDescriptor.ARGUMENT_REQUIRED, DATA_ASCII_OPT, "HTTP POST
ascii data ");
@@ -712,7 +725,11 @@ public class BasicCurlParser {
if
("form-string".equals(option.getDescriptor().getName())) {
request.addFormStringData(key, unquote(value));
} else {
- request.addFormData(key, unquote(value));
+ if (value.charAt(0) == '@') {
+ request.addFormData(key,
FileArgumentHolder.of(unquote(value.substring(1))));
+ } else {
+ request.addFormData(key,
StringArgumentHolder.of(unquote(value)));
+ }
}
request.setMethod("POST");
} else if (option.getDescriptor().getId() == USER_AGENT_OPT) {
diff --git
a/src/protocol/http/src/main/java/org/apache/jmeter/protocol/http/curl/FileArgumentHolder.java
b/src/protocol/http/src/main/java/org/apache/jmeter/protocol/http/curl/FileArgumentHolder.java
new file mode 100644
index 0000000..a11c652
--- /dev/null
+++
b/src/protocol/http/src/main/java/org/apache/jmeter/protocol/http/curl/FileArgumentHolder.java
@@ -0,0 +1,80 @@
+/*
+ * 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.jmeter.protocol.http.curl;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.Objects;
+
+import org.apache.commons.lang3.tuple.Pair;
+
+public class FileArgumentHolder implements ArgumentHolder {
+ private String name;
+ private Map<String, String> metadata;
+
+ private FileArgumentHolder(String name, Map<String, String> metadata) {
+ this.name = name;
+ this.metadata = metadata;
+ };
+
+ public static FileArgumentHolder of(String name) {
+ if (name == null) {
+ return new FileArgumentHolder("", Collections.emptyMap());
+ }
+ Pair<String, Map<String, String>> parsed = ArgumentHolder.parse(name);
+ return new FileArgumentHolder(parsed.getLeft(), parsed.getRight());
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((name == null) ? 0 : name.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ FileArgumentHolder other = (FileArgumentHolder) obj;
+ return Objects.equals(name, other.name);
+ }
+
+ @Override
+ public String getName() {
+ return this.name;
+ }
+
+ @Override
+ public String toString() {
+ return "FileArgumentHolder(" + name + ", " + metadata + ")";
+ }
+
+ @Override
+ public Map<String, String> getMetadata() {
+ return Collections.unmodifiableMap(metadata);
+ }
+}
diff --git
a/src/protocol/http/src/main/java/org/apache/jmeter/protocol/http/curl/StringArgumentHolder.java
b/src/protocol/http/src/main/java/org/apache/jmeter/protocol/http/curl/StringArgumentHolder.java
new file mode 100644
index 0000000..3c1db0e
--- /dev/null
+++
b/src/protocol/http/src/main/java/org/apache/jmeter/protocol/http/curl/StringArgumentHolder.java
@@ -0,0 +1,74 @@
+/*
+ * 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.jmeter.protocol.http.curl;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.Objects;
+
+import org.apache.commons.lang3.tuple.Pair;
+
+public class StringArgumentHolder implements ArgumentHolder {
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(metadata, name);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ StringArgumentHolder other = (StringArgumentHolder) obj;
+ return Objects.equals(metadata, other.metadata) &&
Objects.equals(name, other.name);
+ }
+
+ private String name;
+ private Map<String, String> metadata;
+
+ private StringArgumentHolder(String name, Map<String, String> metadata) {
+ this.name = name;
+ this.metadata = metadata;
+ }
+
+ public static StringArgumentHolder of(String name) {
+ Pair<String, Map<String, String>> argdata = ArgumentHolder.parse(name);
+ return new StringArgumentHolder(argdata.getLeft(), argdata.getRight());
+ }
+
+ @Override
+ public String getName() {
+ return this.name;
+ }
+
+ public Map<String, String> getMetadata() {
+ return Collections.unmodifiableMap(metadata);
+ }
+
+ @Override
+ public String toString() {
+ return "StringArgumentHolder(" + name + ", " + metadata + ")";
+ }
+}
diff --git
a/src/protocol/http/src/main/java/org/apache/jmeter/protocol/http/gui/action/ParseCurlCommandAction.java
b/src/protocol/http/src/main/java/org/apache/jmeter/protocol/http/gui/action/ParseCurlCommandAction.java
index e03ae17..d610b52 100644
---
a/src/protocol/http/src/main/java/org/apache/jmeter/protocol/http/gui/action/ParseCurlCommandAction.java
+++
b/src/protocol/http/src/main/java/org/apache/jmeter/protocol/http/gui/action/ParseCurlCommandAction.java
@@ -38,7 +38,6 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
-import javax.activation.MimetypesFileTypeMap;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
@@ -52,6 +51,7 @@ import javax.swing.tree.TreePath;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.tuple.Pair;
import org.apache.jmeter.config.Arguments;
import org.apache.jmeter.config.KeystoreConfig;
import org.apache.jmeter.control.Controller;
@@ -79,8 +79,10 @@ import org.apache.jmeter.protocol.http.control.Header;
import org.apache.jmeter.protocol.http.control.HeaderManager;
import org.apache.jmeter.protocol.http.control.StaticHost;
import org.apache.jmeter.protocol.http.control.gui.HttpTestSampleGui;
+import org.apache.jmeter.protocol.http.curl.ArgumentHolder;
import org.apache.jmeter.protocol.http.curl.BasicCurlParser;
import org.apache.jmeter.protocol.http.curl.BasicCurlParser.Request;
+import org.apache.jmeter.protocol.http.curl.FileArgumentHolder;
import org.apache.jmeter.protocol.http.gui.AuthPanel;
import org.apache.jmeter.protocol.http.gui.CookiePanel;
import org.apache.jmeter.protocol.http.gui.DNSCachePanel;
@@ -101,6 +103,7 @@ import
org.apache.jmeter.visualizers.ViewResultsFullVisualizer;
import org.apache.jorphan.collections.HashTree;
import org.apache.jorphan.gui.ComponentUtil;
import org.apache.jorphan.gui.JMeterUIDefaults;
+import org.apache.tika.Tika;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -118,6 +121,7 @@ public class ParseCurlCommandAction extends AbstractAction
implements MenuCreato
private static final String CREATE_REQUEST = "CREATE_REQUEST";
private static final String TYPE_FORM = ";type=";
private static final String CERT = "cert";
+ private Logger log = LoggerFactory.getLogger(getClass());
/** A panel allowing results to be saved. */
private FilePanel filePanel = null;
static {
@@ -126,6 +130,7 @@ public class ParseCurlCommandAction extends AbstractAction
implements MenuCreato
private JSyntaxTextArea cURLCommandTA;
private JLabel statusText;
private JCheckBox uploadCookiesCheckBox;
+ private final Tika tika = new Tika();
public ParseCurlCommandAction() {
super();
}
@@ -344,9 +349,8 @@ public class ParseCurlCommandAction extends AbstractAction
implements MenuCreato
headerManager.setProperty(TestElement.GUI_CLASS,
HeaderPanel.class.getName());
headerManager.setProperty(TestElement.NAME, "HTTP HeaderManager");
headerManager.setProperty(TestElement.COMMENTS, getDefaultComment());
- Map<String, String> map = request.getHeaders();
boolean hasAcceptEncoding = false;
- for (Map.Entry<String, String> header : map.entrySet()) {
+ for (Pair<String, String> header : request.getHeaders()) {
String key = header.getKey();
hasAcceptEncoding = hasAcceptEncoding ||
key.equalsIgnoreCase(ACCEPT_ENCODING);
headerManager.getHeaders().addItem(new Header(key,
header.getValue()));
@@ -515,33 +519,39 @@ public class ParseCurlCommandAction extends
AbstractAction implements MenuCreato
throw new IllegalArgumentException("--form and --data can't appear
in the same command");
}
List<HTTPFileArg> httpFileArgs = new ArrayList<>();
- for (Map.Entry<String, String> entry :
request.getFormStringData().entrySet()) {
+ for (Pair<String, String> entry : request.getFormStringData()) {
String formName = entry.getKey();
String formValue = entry.getValue();
httpSampler.addNonEncodedArgument(formName, formValue, "");
}
- for (Map.Entry<String, String> entry :
request.getFormData().entrySet()) {
+ for (Pair<String, ArgumentHolder> entry : request.getFormData()) {
String formName = entry.getKey();
- String formValue = entry.getValue();
- boolean isContainsFile = "@".equals(formValue.substring(0, 1));
- boolean isContainsContentType =
formValue.toLowerCase().contains(TYPE_FORM);
- if (isContainsFile) {
- formValue = unquote(formValue.substring(1,
formValue.length()));
+ ArgumentHolder formValueObject = entry.getValue();
+ String formValue = formValueObject.getName();
+ if (formValueObject instanceof FileArgumentHolder) {
String contentType;
- if (isContainsContentType) {
- String[] formValueWithType = formValue.split(TYPE_FORM);
- formValue = formValueWithType[0];
- contentType = formValueWithType[1];
+ if (formValueObject.hasContenType()) {
+ contentType = formValueObject.getContentType();
} else {
- contentType = new
MimetypesFileTypeMap().getContentType(formValue);
+ try {
+ final File contentFile = new File(formValue);
+ if (contentFile.canRead()) {
+ contentType = tika.detect(contentFile);
+ } else {
+ log.info("Can not read file {}, so guessing
contentType by extension.", formValue);
+ contentType = tika.detect(formValue);
+ }
+ } catch (IOException e) {
+ log.info(
+ "Could not detect contentType for file {} by
content, so falling back to detection by filename",
+ formValue);
+ contentType = tika.detect(formValue);
+ }
}
httpFileArgs.add(new HTTPFileArg(formValue, formName,
contentType));
} else {
- if (isContainsContentType) {
- String[] formValueWithType = formValue.split(TYPE_FORM);
- formValue = formValueWithType[0];
- String contentType = formValueWithType[1];
- httpSampler.addNonEncodedArgument(formName, formValue, "",
contentType);
+ if (formValueObject.hasContenType()) {
+ httpSampler.addNonEncodedArgument(formName, formValue, "",
formValueObject.getContentType());
} else {
httpSampler.addNonEncodedArgument(formName, formValue, "");
}
@@ -552,13 +562,6 @@ public class ParseCurlCommandAction extends AbstractAction
implements MenuCreato
}
}
- private String unquote(String substring) {
- if (substring.charAt(0) == '"') {
- return substring.substring(1, substring.length() -
1).replaceAll("\\\\(.)", "$1");
- }
- return substring;
- }
-
private void createProxyServer(Request request, HTTPSamplerProxy
httpSampler) {
Map<String, String> proxyServer = request.getProxyServer();
for (Map.Entry<String, String> proxyPara : proxyServer.entrySet()) {
diff --git
a/src/protocol/http/src/test/java/org/apache/jmeter/curl/BasicCurlParserTest.java
b/src/protocol/http/src/test/java/org/apache/jmeter/curl/BasicCurlParserTest.java
index adfa954..11bb1ef 100644
---
a/src/protocol/http/src/test/java/org/apache/jmeter/curl/BasicCurlParserTest.java
+++
b/src/protocol/http/src/test/java/org/apache/jmeter/curl/BasicCurlParserTest.java
@@ -27,11 +27,14 @@ import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.List;
-import java.util.Map;
import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang3.tuple.Pair;
import org.apache.jmeter.protocol.http.control.Cookie;
+import org.apache.jmeter.protocol.http.curl.ArgumentHolder;
import org.apache.jmeter.protocol.http.curl.BasicCurlParser;
+import org.apache.jmeter.protocol.http.curl.FileArgumentHolder;
+import org.apache.jmeter.protocol.http.curl.StringArgumentHolder;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
@@ -57,10 +60,10 @@ public class BasicCurlParserTest {
assertEquals(5, request.getHeaders().size());
assertTrue(request.isCompressed());
assertEquals("GET", request.getMethod());
- String resParser = "Request [compressed=true,
url=http://jmeter.apache.org/, method=GET, headers={User-Agent=Mozilla/5.0 "
- + "(Macintosh; Intel Mac OS X 10.11; rv:63.0) Gecko/20100101
Firefox/63.0, Accept=text/html,application/xhtml+xml,"
- + "application/xml;q=0.9,*/*;q=0.8,
Accept-Language=en-US,en;q=0.5, DNT=1, "
- + "Upgrade-Insecure-Requests=1}]";
+ String resParser = "Request [compressed=true,
url=http://jmeter.apache.org/, method=GET, headers=[(User-Agent,Mozilla/5.0 "
+ +"(Macintosh; Intel Mac OS X 10.11; rv:63.0) Gecko/20100101
Firefox/63.0), (Accept,text/html,application/xhtml+xml,"
+ + "application/xml;q=0.9,*/*;q=0.8),
(Accept-Language,en-US,en;q=0.5), (DNT,1), "
+ + "(Upgrade-Insecure-Requests,1)]]";
assertEquals(resParser, request.toString(),
"The method 'toString' should get all parameters correctly");
}
@@ -139,7 +142,7 @@ public class BasicCurlParserTest {
String cmdLine = "";
BasicCurlParser basicCurlParser = new BasicCurlParser();
BasicCurlParser.Request request = basicCurlParser.parse(cmdLine);
- assertEquals("Request [compressed=false, url=null, method=GET,
headers={}]", request.toString(),
+ assertEquals("Request [compressed=false, url=null, method=GET,
headers=[]]", request.toString(),
"The method 'translateCommandline' should return 'null' when
command is empty, ");
}
@@ -208,7 +211,7 @@ public class BasicCurlParserTest {
BasicCurlParser.Request request = basicCurlParser.parse(cmdLine);
assertEquals(5, request.getHeaders().size(),
"With method 'parser', the quantity of Headers should be 5'");
- assertEquals("Mozilla/5.0", request.getHeaders().get("User-Agent"),
+ assertTrue(request.getHeaders().contains(Pair.of("User-Agent",
"Mozilla/5.0")),
"With method 'parser', Headers need to add 'user-agent' with
value 'Mozilla/5.0' ");
}
@@ -319,6 +322,15 @@ public class BasicCurlParserTest {
}
@Test
+ public void testDuplicatedKeyInData() {
+ String cmdLine = "curl 'https://example.invalid' "
+ + "-H 'cache-control: no-cache' --data 'name=one' --data
'name=two' ";
+ BasicCurlParser basicCurlParser = new BasicCurlParser();
+ BasicCurlParser.Request request = basicCurlParser.parse(cmdLine);
+ assertEquals("name=one&name=two", request.getPostData());
+ }
+
+ @Test
public void testDataReadFromFile() throws IOException {
String encoding = StandardCharsets.UTF_8.name();
FileUtils.writeStringToFile(tempFile, "name=test" +
System.lineSeparator(), encoding, true);
@@ -417,19 +429,29 @@ public class BasicCurlParserTest {
+ "-H 'cache-control: no-cache' -F 'test=name' -F
'test1=name1' ";
BasicCurlParser basicCurlParser = new BasicCurlParser();
BasicCurlParser.Request request = basicCurlParser.parse(cmdLine);
- Map<String, String> res = request.getFormData();
- assertEquals("name1", res.get("test1"),
+ List<Pair<String,ArgumentHolder>> res = request.getFormData();
+ assertTrue(res.contains(Pair.of("test1",
StringArgumentHolder.of("name1"))),
"With method 'parser', we should post form data");
}
@Test
+ public void testFormWithEmptyValue() {
+ String cmdLine = "curl 'https://example.invalid' -F 'test=\"\"' ";
+ BasicCurlParser basicCurlParser = new BasicCurlParser();
+ BasicCurlParser.Request request = basicCurlParser.parse(cmdLine);
+ List<Pair<String,ArgumentHolder>> res = request.getFormData();
+ assertTrue(res.contains(Pair.of("test", StringArgumentHolder.of(""))),
+ "With method 'parser', we should post form data: " +
request.getFormData());
+ }
+
+ @Test
public void testFormWithQuotedValue() {
String cmdLine = "curl 'https://www.exaple.invalid/' "
+ "--form 'test=\"something quoted\"'";
BasicCurlParser basicCurlParser = new BasicCurlParser();
BasicCurlParser.Request request = basicCurlParser.parse(cmdLine);
- Map<String, String> res = request.getFormData();
- assertEquals("something quoted", res.get("test"),
+ List<Pair<String,ArgumentHolder>> res = request.getFormData();
+ assertTrue(res.contains(Pair.of("test",
StringArgumentHolder.of("something quoted"))),
"With method 'form', we should post form data");
}
@@ -439,8 +461,8 @@ public class BasicCurlParserTest {
+ "--form 'test=\"something \\\"quoted\\\"\"'";
BasicCurlParser basicCurlParser = new BasicCurlParser();
BasicCurlParser.Request request = basicCurlParser.parse(cmdLine);
- Map<String, String> res = request.getFormData();
- assertEquals("something \"quoted\"", res.get("test"),
+ List<Pair<String,ArgumentHolder>> res = request.getFormData();
+ assertTrue(res.contains(Pair.of("test",
StringArgumentHolder.of("something \"quoted\""))),
"With method 'form', we should post form data");
}
@@ -451,8 +473,20 @@ public class BasicCurlParserTest {
+ "--form 'image=@\"/some/file.jpg\"'";
BasicCurlParser basicCurlParser = new BasicCurlParser();
BasicCurlParser.Request request = basicCurlParser.parse(cmdLine);
- Map<String, String> res = request.getFormData();
- assertEquals("@\"/some/file.jpg\"", res.get("image"),
+ List<Pair<String,ArgumentHolder>> res = request.getFormData();
+ assertTrue(res.contains(Pair.of("image",
FileArgumentHolder.of("/some/file.jpg"))),
+ "With method 'form', we should post form data: " +
request.getFormData());
+ }
+
+ @Test
+ public void testFormWithQuotedNotFilename() {
+ // The quotes will be removed later by the consumer, which is
ParseCurlCommandAction
+ String cmdLine = "curl 'https://www.exaple.invalid/' "
+ + "--form 'image=\"@/some/file.jpg\"'";
+ BasicCurlParser basicCurlParser = new BasicCurlParser();
+ BasicCurlParser.Request request = basicCurlParser.parse(cmdLine);
+ List<Pair<String,ArgumentHolder>> res = request.getFormData();
+ assertTrue(res.contains(Pair.of("image",
StringArgumentHolder.of("@/some/file.jpg"))),
"With method 'form', we should post form data");
}
@@ -462,9 +496,9 @@ public class BasicCurlParserTest {
+ "-H 'cache-control: no-cache' --form-string
'image=@C:\\Test\\test.jpg' ";
BasicCurlParser basicCurlParser = new BasicCurlParser();
BasicCurlParser.Request request = basicCurlParser.parse(cmdLine);
- Map<String, String> res = request.getFormStringData();
- assertEquals("@C:\\Test\\test.jpg", res.get("image"),
- "With method 'parser', we should post form data");
+ List<Pair<String,String>> res = request.getFormStringData();
+ assertTrue(res.contains(Pair.of("image", "@C:\\Test\\test.jpg")),
+ "With method 'parser', we should post form data: " +
request.getFormStringData());
}
@Test
@@ -556,7 +590,7 @@ public class BasicCurlParserTest {
String cmdLine = "curl 'http://jmeter.apache.org/' --referer
'www.baidu.com'";
BasicCurlParser basicCurlParser = new BasicCurlParser();
BasicCurlParser.Request request = basicCurlParser.parse(cmdLine);
- assertEquals("www.baidu.com", request.getHeaders().get("Referer"));
+ assertTrue(request.getHeaders().contains(Pair.of("Referer",
"www.baidu.com")));
}
@Test