From d0770bf8191ffe58fb511b4d685cbbca0f27eec1 Mon Sep 17 00:00:00 2001 From: Ludovic Heitz Date: Wed, 26 Jul 2023 14:36:22 +0200 Subject: [PATCH 1/2] Use Netty HttpPostRequestEncoder with "HTML5" encoder mode to prevent "multipart/mixed" body --- .../main/java/com/intuit/karate/http/MultiPartBuilder.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/karate-core/src/main/java/com/intuit/karate/http/MultiPartBuilder.java b/karate-core/src/main/java/com/intuit/karate/http/MultiPartBuilder.java index 614685849..cc87fbb0b 100644 --- a/karate-core/src/main/java/com/intuit/karate/http/MultiPartBuilder.java +++ b/karate-core/src/main/java/com/intuit/karate/http/MultiPartBuilder.java @@ -34,7 +34,10 @@ import io.netty.handler.codec.http.HttpMethod; import io.netty.handler.codec.http.HttpVersion; import io.netty.handler.codec.http.multipart.Attribute; +import io.netty.handler.codec.http.multipart.DefaultHttpDataFactory; import io.netty.handler.codec.http.multipart.HttpPostRequestEncoder; +import io.netty.handler.codec.http.multipart.HttpPostRequestEncoder.EncoderMode; +import io.netty.util.CharsetUtil; import io.netty.handler.codec.http.multipart.InterfaceHttpData; import io.netty.handler.codec.http.multipart.MemoryFileUpload; import java.io.File; @@ -92,7 +95,7 @@ public MultiPartBuilder(boolean multipart, HttpClient client) { this.multipart = multipart; DefaultFullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.valueOf("POST"), "/"); try { - encoder = new HttpPostRequestEncoder(request, multipart); + encoder = new HttpPostRequestEncoder(new DefaultHttpDataFactory(DefaultHttpDataFactory.MINSIZE), request, multipart, CharsetUtil.UTF_8, EncoderMode.HTML5); } catch (Exception e) { throw new RuntimeException(e); } From 214a36f9a82f916e044570863e35ad30f47da2a5 Mon Sep 17 00:00:00 2001 From: Ludovic Heitz Date: Thu, 27 Jul 2023 11:00:23 +0200 Subject: [PATCH 2/2] test: Check request body has no "multipart/mixed" part --- .../test/java/com/intuit/karate/TestUtils.java | 5 +++++ .../karate/core/KarateMockHandlerTest.java | 17 +++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/karate-core/src/test/java/com/intuit/karate/TestUtils.java b/karate-core/src/test/java/com/intuit/karate/TestUtils.java index 04ef04ff9..381444c4a 100644 --- a/karate-core/src/test/java/com/intuit/karate/TestUtils.java +++ b/karate-core/src/test/java/com/intuit/karate/TestUtils.java @@ -31,6 +31,11 @@ public static void matchContains(Object actual, Object expected) { Match.Result mr = Match.evaluate(actual).contains(expected); assertTrue(mr.pass, mr.message); } + + public static void notContains(Object actual, Object expected) { + Match.Result mr = Match.evaluate(actual).isNotContaining(expected); + assertTrue(mr.pass, mr.message); + } public static ScenarioEngine engine() { return new ScenarioEngine(new Config(), runtime(), new HashMap(), new Logger()); diff --git a/karate-core/src/test/java/com/intuit/karate/core/KarateMockHandlerTest.java b/karate-core/src/test/java/com/intuit/karate/core/KarateMockHandlerTest.java index e93f18e9a..2a2b4f6b0 100644 --- a/karate-core/src/test/java/com/intuit/karate/core/KarateMockHandlerTest.java +++ b/karate-core/src/test/java/com/intuit/karate/core/KarateMockHandlerTest.java @@ -390,6 +390,23 @@ void testMultiPartFile() { matchVar("response", "{ foo: [{ name: 'foo', value: '#notnull', contentType: 'text/plain', charset: 'UTF-8', filename: 'foo.txt', transferEncoding: '7bit' }] }"); } + @Test + void testMultiPartFiles() { + background().scenario( + "pathMatches('/hello')", + "def response = requestParts"); + run( + URL_STEP, + "def file1 = { name: 'file', filename: 'file1.txt', value: 'Hello 1' }", + "def file2 = { name: 'file', filename: 'file2.txt', value: 'Hello 2' }", + "multipart files ([file1, file2])", + "path 'hello'", + "method post" + ); + runtime.engine.assign(AssignType.STRING, "prevReqBody", "karate.prevRequest.body", false); + notContains(get("prevReqBody"), "multipart/mixed"); + } + @Test void testMultiPartFileNullCharset() { background().scenario(