diff --git a/vividus-allure-adaptor/src/main/resources/allure-customization/webjars/bootstrap/3.4.1/fonts/clipboard.svg b/vividus-allure-adaptor/src/main/resources/allure-customization/webjars/bootstrap/3.4.1/fonts/clipboard.svg
new file mode 100644
index 0000000000..b92f42a5bc
--- /dev/null
+++ b/vividus-allure-adaptor/src/main/resources/allure-customization/webjars/bootstrap/3.4.1/fonts/clipboard.svg
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/vividus-plugin-rest-api/src/main/java/org/vividus/http/CurlUtils.java b/vividus-plugin-rest-api/src/main/java/org/vividus/http/CurlUtils.java
new file mode 100644
index 0000000000..14cedda1c5
--- /dev/null
+++ b/vividus-plugin-rest-api/src/main/java/org/vividus/http/CurlUtils.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2019-2024 the original author or authors.
+ *
+ * Licensed 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
+ *
+ * https://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.vividus.http;
+
+import java.net.URISyntaxException;
+import java.nio.charset.Charset;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Stream;
+
+import org.apache.hc.core5.http.Header;
+import org.apache.hc.core5.http.HttpRequest;
+
+public final class CurlUtils
+{
+ private static final Pattern NAME_FILE_NAME_PATTERN = Pattern.compile("name=\"(.+)\"; filename=\"(.+)\"");
+ private static final Pattern NAME_CONTENT_PATTERN = Pattern.compile("name=\"(.+)\"\nContent-Type:.+\n\n(.*)");
+ private static final String SINGLE_QUOTE = "'";
+ private static final String END_OF_LINE = " \\\n";
+ private static final String DOUBLE_QUOTE = "\"";
+
+ private CurlUtils()
+ {
+ }
+
+ public static String buildCurlCommand(HttpRequest request, String mimeType,
+ Charset charset, byte[] body) throws URISyntaxException
+ {
+ StringBuilder curlCommand = new StringBuilder("curl ");
+ appendMethodAndUri(curlCommand, request);
+ appendHeaders(curlCommand, request.getHeaders());
+ if (body != null)
+ {
+ appendBody(curlCommand, mimeType, charset, body);
+ }
+ return curlCommand.toString();
+ }
+
+ private static void appendMethodAndUri(StringBuilder curlCommand, HttpRequest request) throws URISyntaxException
+ {
+ curlCommand.append("-X ").append(request.getMethod()).append(" '")
+ .append(request.getUri()).append(SINGLE_QUOTE);
+ }
+
+ private static void appendHeaders(StringBuilder curlCommand, Header[] headers)
+ {
+ Stream.of(headers).forEach(h -> curlCommand.append(END_OF_LINE)
+ .append("-H '").append(h.getName()).append(": ").append(h.getValue()).append(SINGLE_QUOTE));
+ }
+
+ private static void appendBody(StringBuilder curlCommand, String mimeType, Charset charset, byte[] body)
+ {
+ String bodyAsString = new String(body, charset);
+ if (mimeType.contains("multipart"))
+ {
+ appendMultipartData(curlCommand, bodyAsString);
+ return;
+ }
+ curlCommand.append(END_OF_LINE).append("-d '").append(bodyAsString).append(SINGLE_QUOTE);
+ }
+
+ private static void appendMultipartData(StringBuilder curlCommand, String bodyAsString)
+ {
+ String regex = bodyAsString.split("\\R", 2)[0];
+ String[] formDataArray = bodyAsString.split(regex + ".*");
+
+ Stream.of(formDataArray).forEach(e ->
+ {
+ Matcher matcher = NAME_FILE_NAME_PATTERN.matcher(e);
+ String formStringStart = "-F \"";
+ if (matcher.find())
+ {
+ curlCommand.append(END_OF_LINE).append(formStringStart).append(matcher.group(1))
+ .append("=@").append(matcher.group(2)).append(DOUBLE_QUOTE);
+ }
+ else
+ {
+ matcher = NAME_CONTENT_PATTERN.matcher(e);
+ if (matcher.find())
+ {
+ curlCommand.append(END_OF_LINE).append(formStringStart).append(matcher.group(1))
+ .append("=").append(matcher.group(2)).append(DOUBLE_QUOTE);
+ }
+ }
+ });
+ }
+}
diff --git a/vividus-plugin-rest-api/src/main/java/org/vividus/http/PublishingAttachmentInterceptor.java b/vividus-plugin-rest-api/src/main/java/org/vividus/http/PublishingAttachmentInterceptor.java
index 02373c8701..2e69ab2c8a 100644
--- a/vividus-plugin-rest-api/src/main/java/org/vividus/http/PublishingAttachmentInterceptor.java
+++ b/vividus-plugin-rest-api/src/main/java/org/vividus/http/PublishingAttachmentInterceptor.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2019-2023 the original author or authors.
+ * Copyright 2019-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,6 +18,8 @@
import java.io.ByteArrayOutputStream;
import java.io.IOException;
+import java.net.URISyntaxException;
+import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
@@ -30,6 +32,7 @@
import org.apache.hc.core5.http.HttpEntityContainer;
import org.apache.hc.core5.http.HttpRequest;
import org.apache.hc.core5.http.HttpRequestInterceptor;
+import org.apache.hc.core5.http.io.entity.ByteArrayEntity;
import org.apache.hc.core5.http.protocol.HttpContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -53,6 +56,7 @@ public void process(HttpRequest request, EntityDetails entityDetails, HttpContex
{
byte[] body = null;
String mimeType = null;
+ Charset charset = StandardCharsets.UTF_8;
if (request instanceof HttpEntityContainer httpEntityContainer)
{
HttpEntity entity = httpEntityContainer.getEntity();
@@ -63,6 +67,10 @@ public void process(HttpRequest request, EntityDetails entityDetails, HttpContex
Optional.ofNullable(ContentType.parseLenient(entity.getContentType()))
.orElse(ContentType.DEFAULT_TEXT).getMimeType()
);
+ if (entity instanceof ByteArrayEntity)
+ {
+ charset = StandardCharsets.US_ASCII;
+ }
try (ByteArrayOutputStream baos = new ByteArrayOutputStream((int) entity.getContentLength()))
{
// https://github.com/apache/httpcomponents-client/commit/09cefc2b8970eea56d81b1a886d9bb769a48daf3
@@ -75,25 +83,37 @@ public void process(HttpRequest request, EntityDetails entityDetails, HttpContex
}
}
}
- attachApiMessage("Request: " + request, request.getHeaders(), body, mimeType, -1);
+ String curlCommand = null;
+ try
+ {
+ curlCommand = CurlUtils.buildCurlCommand(request, mimeType, charset, body);
+ }
+ catch (URISyntaxException e)
+ {
+ LOGGER.error("Error is occurred on building cURL command", e);
+ }
+ attachApiMessage("Request: " + request, request.getHeaders(), body, mimeType, -1, curlCommand);
}
@Override
- public void handle(HttpResponse response) throws IOException
+ public void handle(HttpResponse response)
{
Header[] headers = response.getResponseHeaders();
String attachmentTitle = String.format("Response: %s %s", response.getMethod(), response.getFrom());
String mimeType = MimeTypeUtils.getMimeTypeFromHeadersWithDefault(headers);
- attachApiMessage(attachmentTitle, headers, response.getResponseBody(), mimeType, response.getStatusCode());
+ attachApiMessage(attachmentTitle, headers, response.getResponseBody(), mimeType,
+ response.getStatusCode(), null);
}
- private void attachApiMessage(String title, Header[] headers, byte[] body, String mimeType, int statusCode)
+ private void attachApiMessage(String title, Header[] headers, byte[] body, String mimeType,
+ int statusCode, String curlCommand)
{
Map dataMap = new HashMap<>();
dataMap.put("headers", headers);
dataMap.put("body", body != null ? new String(body, StandardCharsets.UTF_8) : null);
dataMap.put("bodyContentType", mimeType);
dataMap.put("statusCode", statusCode);
+ dataMap.put("curlCommand", curlCommand);
attachmentPublisher.publishAttachment("/org/vividus/http/attachment/api-message.ftl", dataMap, title);
}
diff --git a/vividus-plugin-rest-api/src/main/resources/org/vividus/http/attachment/api-message.ftl b/vividus-plugin-rest-api/src/main/resources/org/vividus/http/attachment/api-message.ftl
index 755e39dea2..bcacda0eab 100644
--- a/vividus-plugin-rest-api/src/main/resources/org/vividus/http/attachment/api-message.ftl
+++ b/vividus-plugin-rest-api/src/main/resources/org/vividus/http/attachment/api-message.ftl
@@ -94,6 +94,21 @@
#if>
+
+ <#if curlCommand??>
+
+ #if>
@@ -110,6 +125,11 @@
hljs.highlightElement(e);
});
});
+
+ function copyCurlCommand() {
+ var text = document.querySelector('#collapse-curl code').textContent;
+ navigator.clipboard.writeText(text);
+ }