diff --git a/independent-projects/resteasy-reactive/server/vertx/src/main/java/org/jboss/resteasy/reactive/server/vertx/ResteasyReactiveOutputStream.java b/independent-projects/resteasy-reactive/server/vertx/src/main/java/org/jboss/resteasy/reactive/server/vertx/ResteasyReactiveOutputStream.java index 90d13ba225ec0..d5cf25c8240fd 100644 --- a/independent-projects/resteasy-reactive/server/vertx/src/main/java/org/jboss/resteasy/reactive/server/vertx/ResteasyReactiveOutputStream.java +++ b/independent-projects/resteasy-reactive/server/vertx/src/main/java/org/jboss/resteasy/reactive/server/vertx/ResteasyReactiveOutputStream.java @@ -6,12 +6,15 @@ import io.vertx.core.Context; import io.vertx.core.Handler; import io.vertx.core.buffer.Buffer; +import io.vertx.core.http.HttpHeaders; import io.vertx.core.http.HttpServerRequest; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InterruptedIOException; import java.io.OutputStream; +import javax.ws.rs.core.MultivaluedMap; import org.jboss.logging.Logger; +import org.jboss.resteasy.reactive.server.core.LazyResponse; import org.jboss.resteasy.reactive.server.core.ResteasyReactiveRequestContext; public class ResteasyReactiveOutputStream extends OutputStream { @@ -233,12 +236,24 @@ private void prepareWrite(ByteBuf buffer, boolean finished) throws IOException { } else { context.serverResponse().setResponseHeader(HttpHeaderNames.CONTENT_LENGTH, "" + buffer.readableBytes()); } - } else if (!request.response().headers().contains(HttpHeaderNames.CONTENT_LENGTH)) { + } else if (!contentLengthSet()) { request.response().setChunked(true); } } } + private boolean contentLengthSet() { + if (request.response().headers().contains(HttpHeaderNames.CONTENT_LENGTH)) { + return true; + } + LazyResponse lazyResponse = context.getResponse(); + if (!lazyResponse.isCreated()) { + return false; + } + MultivaluedMap responseHeaders = lazyResponse.get().getHeaders(); + return (responseHeaders != null) && responseHeaders.containsKey(HttpHeaders.CONTENT_LENGTH); + } + /** * {@inheritDoc} */ diff --git a/independent-projects/resteasy-reactive/server/vertx/src/test/java/org/jboss/resteasy/reactive/server/vertx/test/response/ContentLengthTest.java b/independent-projects/resteasy-reactive/server/vertx/src/test/java/org/jboss/resteasy/reactive/server/vertx/test/response/ContentLengthTest.java new file mode 100644 index 0000000000000..2faf6d56d628e --- /dev/null +++ b/independent-projects/resteasy-reactive/server/vertx/src/test/java/org/jboss/resteasy/reactive/server/vertx/test/response/ContentLengthTest.java @@ -0,0 +1,56 @@ +package org.jboss.resteasy.reactive.server.vertx.test.response; + +import static io.restassured.RestAssured.when; +import static org.hamcrest.Matchers.greaterThan; +import static org.hamcrest.core.IsNull.nullValue; + +import java.io.ByteArrayInputStream; +import java.nio.charset.StandardCharsets; +import java.util.Collections; +import java.util.UUID; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import org.jboss.resteasy.reactive.server.vertx.test.framework.ResteasyReactiveUnitTest; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +public class ContentLengthTest { + + private static final int NUMBER_OF_COPIES = 500; + + @RegisterExtension + static ResteasyReactiveUnitTest runner = new ResteasyReactiveUnitTest() + .withApplicationRoot((jar) -> jar + .addClasses(FileResource.class)); + + @Test + void testResponseHeaders() { + when() + .get("/file") + .then() + .statusCode(200) + .header(HttpHeaders.CONTENT_LENGTH, + greaterThan( + "" + (NUMBER_OF_COPIES * UUID.randomUUID().toString().getBytes(StandardCharsets.UTF_8).length))) + .header("transfer-encoding", nullValue()); + } + + @Path("/file") + public static class FileResource { + + @GET + @Produces(MediaType.TEXT_PLAIN) + public Response hello() { + byte[] bytes = String.join(";", Collections.nCopies(NUMBER_OF_COPIES, UUID.randomUUID().toString())) + .getBytes(StandardCharsets.UTF_8); + return Response.ok(new ByteArrayInputStream(bytes), "text/plain") + .header(HttpHeaders.CONTENT_LENGTH, bytes.length) + .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename = " + "uuid.txt") + .build(); + } + } +}