From 350965b6f19b322efb38d7babac505b23ad39fab Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Tue, 23 Nov 2021 19:48:34 +0200 Subject: [PATCH] Fix InputStream handling as Response entity in RESTEasy Classic Fixes: #21602 --- ...ResponseLargePayloadWithRemainderTest.java | 43 +++++++++++++++++++ ...ponseLargePayloadWithoutRemainderTest.java | 43 +++++++++++++++++++ .../test/InputStreamResponseTest.java | 40 +++++++++++++++++ .../runtime/standalone/VertxOutputStream.java | 14 ++++-- 4 files changed, 137 insertions(+), 3 deletions(-) create mode 100644 extensions/resteasy-classic/resteasy/deployment/src/test/java/io/quarkus/resteasy/test/InputStreamResponseLargePayloadWithRemainderTest.java create mode 100644 extensions/resteasy-classic/resteasy/deployment/src/test/java/io/quarkus/resteasy/test/InputStreamResponseLargePayloadWithoutRemainderTest.java create mode 100644 extensions/resteasy-classic/resteasy/deployment/src/test/java/io/quarkus/resteasy/test/InputStreamResponseTest.java diff --git a/extensions/resteasy-classic/resteasy/deployment/src/test/java/io/quarkus/resteasy/test/InputStreamResponseLargePayloadWithRemainderTest.java b/extensions/resteasy-classic/resteasy/deployment/src/test/java/io/quarkus/resteasy/test/InputStreamResponseLargePayloadWithRemainderTest.java new file mode 100644 index 0000000000000..e7d4640d8d24b --- /dev/null +++ b/extensions/resteasy-classic/resteasy/deployment/src/test/java/io/quarkus/resteasy/test/InputStreamResponseLargePayloadWithRemainderTest.java @@ -0,0 +1,43 @@ +package io.quarkus.resteasy.test; + +import static io.restassured.RestAssured.when; + +import java.io.ByteArrayInputStream; +import java.nio.charset.StandardCharsets; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Response; + +import org.hamcrest.Matchers; +import org.jboss.shrinkwrap.api.asset.StringAsset; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; + +public class InputStreamResponseLargePayloadWithRemainderTest { + + @RegisterExtension + static QuarkusUnitTest runner = new QuarkusUnitTest() + .withApplicationRoot((jar) -> jar + .addClasses(RootResource.class) + .addAsResource(new StringAsset("quarkus.resteasy.vertx.response-buffer-size=11\n"), + "application.properties")); + + @Test + public void test() { + when().get("/test").then().body(Matchers.is("Hello World!")); + } + + @Path("test") + public static class TestResource { + + @Produces("text/plain") + @GET + public Response test() { + return Response.ok(new ByteArrayInputStream("Hello World!".getBytes(StandardCharsets.UTF_8))).build(); + } + } +} diff --git a/extensions/resteasy-classic/resteasy/deployment/src/test/java/io/quarkus/resteasy/test/InputStreamResponseLargePayloadWithoutRemainderTest.java b/extensions/resteasy-classic/resteasy/deployment/src/test/java/io/quarkus/resteasy/test/InputStreamResponseLargePayloadWithoutRemainderTest.java new file mode 100644 index 0000000000000..13058afdee431 --- /dev/null +++ b/extensions/resteasy-classic/resteasy/deployment/src/test/java/io/quarkus/resteasy/test/InputStreamResponseLargePayloadWithoutRemainderTest.java @@ -0,0 +1,43 @@ +package io.quarkus.resteasy.test; + +import static io.restassured.RestAssured.when; + +import java.io.ByteArrayInputStream; +import java.nio.charset.StandardCharsets; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Response; + +import org.hamcrest.Matchers; +import org.jboss.shrinkwrap.api.asset.StringAsset; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; + +public class InputStreamResponseLargePayloadWithoutRemainderTest { + + @RegisterExtension + static QuarkusUnitTest runner = new QuarkusUnitTest() + .withApplicationRoot((jar) -> jar + .addClasses(RootResource.class) + .addAsResource(new StringAsset("quarkus.resteasy.vertx.response-buffer-size=3\n"), + "application.properties")); + + @Test + public void test() { + when().get("/test").then().body(Matchers.is("Hello World!")); + } + + @Path("test") + public static class TestResource { + + @Produces("text/plain") + @GET + public Response test() { + return Response.ok(new ByteArrayInputStream("Hello World!".getBytes(StandardCharsets.UTF_8))).build(); + } + } +} diff --git a/extensions/resteasy-classic/resteasy/deployment/src/test/java/io/quarkus/resteasy/test/InputStreamResponseTest.java b/extensions/resteasy-classic/resteasy/deployment/src/test/java/io/quarkus/resteasy/test/InputStreamResponseTest.java new file mode 100644 index 0000000000000..bc40117a793d6 --- /dev/null +++ b/extensions/resteasy-classic/resteasy/deployment/src/test/java/io/quarkus/resteasy/test/InputStreamResponseTest.java @@ -0,0 +1,40 @@ +package io.quarkus.resteasy.test; + +import static io.restassured.RestAssured.when; + +import java.io.ByteArrayInputStream; +import java.nio.charset.StandardCharsets; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Response; + +import org.hamcrest.Matchers; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; + +public class InputStreamResponseTest { + + @RegisterExtension + static QuarkusUnitTest runner = new QuarkusUnitTest() + .withApplicationRoot((jar) -> jar + .addClasses(RootResource.class)); + + @Test + public void test() { + when().get("/test").then().body(Matchers.is("Hello World")); + } + + @Path("test") + public static class TestResource { + + @Produces("text/plain") + @GET + public Response test() { + return Response.ok(new ByteArrayInputStream("Hello World".getBytes(StandardCharsets.UTF_8))).build(); + } + } +} diff --git a/extensions/resteasy-classic/resteasy/runtime/src/main/java/io/quarkus/resteasy/runtime/standalone/VertxOutputStream.java b/extensions/resteasy-classic/resteasy/runtime/src/main/java/io/quarkus/resteasy/runtime/standalone/VertxOutputStream.java index 18140d473e712..aa9fcaa8fff2b 100644 --- a/extensions/resteasy-classic/resteasy/runtime/src/main/java/io/quarkus/resteasy/runtime/standalone/VertxOutputStream.java +++ b/extensions/resteasy-classic/resteasy/runtime/src/main/java/io/quarkus/resteasy/runtime/standalone/VertxOutputStream.java @@ -167,13 +167,21 @@ public CompletionStage asyncWrite(final byte[] b, final int off, final int } if (bufferCount == 1) { - pooledBuffer = allocator.allocateBuffer(); - pooledBuffer.writeBytes(b); + if (pooledBuffer == null) { + pooledBuffer = allocator.allocateBuffer(); + } + pooledBuffer.writeBytes(b, 0, len); } else { for (int i = 0; i < bufferCount - 1; i++) { int bufferIndex = i; ret = ret.thenCompose(v -> { - ByteBuf tmpBuf = allocator.allocateBuffer(); + ByteBuf tmpBuf = null; + if ((bufferIndex == 0) && ((pooledBuffer != null))) { + tmpBuf = pooledBuffer; + } + if (tmpBuf == null) { + tmpBuf = allocator.allocateBuffer(); + } tmpBuf.writeBytes(b, bufferIndex * bufferSize, bufferSize); return response.writeNonBlocking(tmpBuf, false); });