From 974edb1cec9db0181e81203455376de0e08a857a Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Wed, 22 Jan 2025 17:46:03 +0200 Subject: [PATCH] Prevent creation of the Response object for ContainerResponseContext Fixes: #45791 --- .../server/test/providers/FileTestCase.java | 14 +++- .../reactive/server/core/LazyResponse.java | 10 +++ .../server/handlers/ResponseHandler.java | 67 +++++++++++-------- .../jaxrs/ContainerResponseContextImpl.java | 8 ++- 4 files changed, 67 insertions(+), 32 deletions(-) diff --git a/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/providers/FileTestCase.java b/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/providers/FileTestCase.java index a7feae8824879..a402407a578f2 100644 --- a/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/providers/FileTestCase.java +++ b/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/providers/FileTestCase.java @@ -7,11 +7,13 @@ import java.nio.file.Path; import java.nio.file.Paths; +import jakarta.ws.rs.container.ContainerResponseContext; import jakarta.ws.rs.core.HttpHeaders; import org.hamcrest.Matchers; import org.jboss.resteasy.reactive.FilePart; import org.jboss.resteasy.reactive.PathPart; +import org.jboss.resteasy.reactive.server.ServerResponseFilter; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; @@ -30,7 +32,7 @@ public class FileTestCase { @RegisterExtension static final QuarkusUnitTest config = new QuarkusUnitTest() .withApplicationRoot((jar) -> jar - .addClasses(FileResource.class, WithWriterInterceptor.class, WriterInterceptor.class)); + .addClasses(FileResource.class, WithWriterInterceptor.class, WriterInterceptor.class, Filters.class)); @Test public void testFiles() throws Exception { @@ -168,4 +170,14 @@ public void testChecks() throws IOException { } catch (IllegalArgumentException x) { } } + + public static class Filters { + + @ServerResponseFilter + public void responseHeaders(ContainerResponseContext responseContext) { + // make sure the use of these methods does not change the response code + responseContext.hasEntity(); + responseContext.getEntity(); + } + } } diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/LazyResponse.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/LazyResponse.java index 0203556f372e9..73b7ef5dde1d5 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/LazyResponse.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/LazyResponse.java @@ -9,6 +9,11 @@ public interface LazyResponse { */ Response get(); + /** + * Gets the response, but makes change to the state of the object + */ + Response transientGet(); + /** * * @return true if the response already exists @@ -37,6 +42,11 @@ public Response get() { return response; } + @Override + public Response transientGet() { + return response; + } + @Override public boolean isCreated() { return true; diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/ResponseHandler.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/ResponseHandler.java index 25116ff3d8f69..44276204ed145 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/ResponseHandler.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/ResponseHandler.java @@ -139,42 +139,51 @@ public void handle(ResteasyReactiveRequestContext requestContext) throws Excepti Response response; + public Response create() { + ResponseBuilderImpl responseBuilder; + if (result instanceof GenericEntity) { + GenericEntity genericEntity = (GenericEntity) result; + requestContext.setGenericReturnType(genericEntity.getType()); + responseBuilder = ResponseBuilderImpl.ok(genericEntity.getEntity()); + } else if (result == null) { + // FIXME: custom status codes depending on method? + responseBuilder = ResponseBuilderImpl.noContent(); + } else { + // FIXME: custom status codes depending on method? + responseBuilder = ResponseBuilderImpl.ok(result); + } + if (responseBuilder.getEntity() != null) { + EncodedMediaType produces = requestContext.getResponseContentType(); + if (produces != null) { + responseBuilder.header(HttpHeaders.CONTENT_TYPE, produces.toString()); + } + } + if (!responseBuilderCustomizers.isEmpty()) { + for (int i = 0; i < responseBuilderCustomizers.size(); i++) { + responseBuilderCustomizers.get(i).customize(responseBuilder); + } + } + if ((responseBuilder instanceof ResponseBuilderImpl)) { + // avoid unnecessary copying of HTTP headers from the Builder to the Response + return ((ResponseBuilderImpl) responseBuilder).build(false); + } else { + return responseBuilder.build(); + } + } + @Override public Response get() { if (response == null) { - ResponseBuilderImpl responseBuilder; - if (result instanceof GenericEntity) { - GenericEntity genericEntity = (GenericEntity) result; - requestContext.setGenericReturnType(genericEntity.getType()); - responseBuilder = ResponseBuilderImpl.ok(genericEntity.getEntity()); - } else if (result == null) { - // FIXME: custom status codes depending on method? - responseBuilder = ResponseBuilderImpl.noContent(); - } else { - // FIXME: custom status codes depending on method? - responseBuilder = ResponseBuilderImpl.ok(result); - } - if (responseBuilder.getEntity() != null) { - EncodedMediaType produces = requestContext.getResponseContentType(); - if (produces != null) { - responseBuilder.header(HttpHeaders.CONTENT_TYPE, produces.toString()); - } - } - if (!responseBuilderCustomizers.isEmpty()) { - for (int i = 0; i < responseBuilderCustomizers.size(); i++) { - responseBuilderCustomizers.get(i).customize(responseBuilder); - } - } - if ((responseBuilder instanceof ResponseBuilderImpl)) { - // avoid unnecessary copying of HTTP headers from the Builder to the Response - response = ((ResponseBuilderImpl) responseBuilder).build(false); - } else { - response = responseBuilder.build(); - } + response = create(); } return response; } + @Override + public Response transientGet() { + return create(); + } + @Override public boolean isCreated() { return response != null; diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/jaxrs/ContainerResponseContextImpl.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/jaxrs/ContainerResponseContextImpl.java index 57429cd9d9be1..6cf85944dbfb5 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/jaxrs/ContainerResponseContextImpl.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/jaxrs/ContainerResponseContextImpl.java @@ -134,14 +134,18 @@ public Builder getLinkBuilder(String relation) { return response().getLinkBuilder(relation); } + protected Response transientResponse() { + return context.getResponse().transientGet(); + } + @Override public boolean hasEntity() { - return response().hasEntity(); + return transientResponse().hasEntity(); } @Override public Object getEntity() { - return response().getEntity(); + return transientResponse().getEntity(); } @Override