From 6e130d18c1c935d3a9c94b5b3b92dbcd793194cd Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Thu, 13 Jan 2022 12:44:53 +0200 Subject: [PATCH] Take response status of aborted request into account in JAX-RS Client Fixes: #22827 (cherry picked from commit c511555f716ead16d5ead2d08ed622eefd48141c) --- .../ClientRequestFilterAbortWithTestCase.java | 74 +++++++++++++++++++ .../ClientSetResponseEntityRestHandler.java | 24 +++++- 2 files changed, 94 insertions(+), 4 deletions(-) create mode 100644 extensions/resteasy-reactive/jaxrs-client-reactive/deployment/src/test/java/io/quarkus/jaxrs/client/reactive/deployment/test/ClientRequestFilterAbortWithTestCase.java diff --git a/extensions/resteasy-reactive/jaxrs-client-reactive/deployment/src/test/java/io/quarkus/jaxrs/client/reactive/deployment/test/ClientRequestFilterAbortWithTestCase.java b/extensions/resteasy-reactive/jaxrs-client-reactive/deployment/src/test/java/io/quarkus/jaxrs/client/reactive/deployment/test/ClientRequestFilterAbortWithTestCase.java new file mode 100644 index 0000000000000..b34b5214ccfb4 --- /dev/null +++ b/extensions/resteasy-reactive/jaxrs-client-reactive/deployment/src/test/java/io/quarkus/jaxrs/client/reactive/deployment/test/ClientRequestFilterAbortWithTestCase.java @@ -0,0 +1,74 @@ +package io.quarkus.jaxrs.client.reactive.deployment.test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.net.URL; + +import javax.enterprise.event.Observes; +import javax.ws.rs.client.Client; +import javax.ws.rs.client.ClientBuilder; +import javax.ws.rs.client.ClientRequestContext; +import javax.ws.rs.client.ClientRequestFilter; +import javax.ws.rs.core.Response; +import javax.ws.rs.ext.Provider; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; +import io.quarkus.test.common.http.TestHTTPResource; +import io.vertx.core.Handler; +import io.vertx.ext.web.Router; +import io.vertx.ext.web.RoutingContext; + +public class ClientRequestFilterAbortWithTestCase { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .withApplicationRoot((jar) -> jar + .addClasses(Endpoint.class)); + + @TestHTTPResource + URL url; + + private Client client; + + @BeforeEach + public void before() { + client = ClientBuilder.newClient().register(TestClientRequestFilter.class); + } + + @AfterEach + public void after() { + client.close(); + } + + @Test + public void test() { + Response response = client.target(url.toExternalForm() + "/hello").request().get(); + assertEquals(999, response.getStatus()); + } + + public static class Endpoint { + + public void setup(@Observes Router router) { + router.route("/hello").handler(new Handler<>() { + @Override + public void handle(RoutingContext event) { + event.response().setStatusCode(200).end(); + } + }); + } + } + + @Provider + public static class TestClientRequestFilter implements ClientRequestFilter { + + @Override + public void filter(ClientRequestContext requestContext) { + requestContext.abortWith(Response.status(999).build()); + } + } +} diff --git a/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/handlers/ClientSetResponseEntityRestHandler.java b/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/handlers/ClientSetResponseEntityRestHandler.java index b55e8b6c5ebb4..96404a32cb0a7 100644 --- a/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/handlers/ClientSetResponseEntityRestHandler.java +++ b/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/handlers/ClientSetResponseEntityRestHandler.java @@ -18,20 +18,36 @@ public class ClientSetResponseEntityRestHandler implements ClientRestHandler { @Override public void handle(RestClientRequestContext context) throws Exception { + ClientRequestContextImpl requestContext = context.getClientRequestContext(); ClientResponseContextImpl responseContext = new ClientResponseContextImpl(context); if (context.isCheckSuccessfulFamily()) { - if (Response.Status.Family.familyOf(context.getResponseStatus()) != Response.Status.Family.SUCCESSFUL) { - throw new WebClientApplicationException(context.getResponseStatus(), context.getResponseReasonPhrase()); + int effectiveResponseStatus = determineEffectiveResponseStatus(context, requestContext); + if (Response.Status.Family.familyOf(effectiveResponseStatus) != Response.Status.Family.SUCCESSFUL) { + throw new WebClientApplicationException(effectiveResponseStatus, context.getResponseReasonPhrase()); } } - ClientRequestContextImpl requestContext = context.getClientRequestContext(); + // the spec doesn't really say this, but the TCK checks that the abortWith entity ends up read // so we have to write it, but without filters/interceptors - if (requestContext != null && requestContext.getAbortedWith() != null) { + if (isAbortedWith(requestContext)) { setExistingEntity(requestContext.getAbortedWith(), responseContext, context); } } + private int determineEffectiveResponseStatus(RestClientRequestContext context, ClientRequestContextImpl requestContext) { + int effectiveResponseStatus = context.getResponseStatus(); + if (effectiveResponseStatus == 0) { + if (isAbortedWith(requestContext)) { + effectiveResponseStatus = requestContext.getAbortedWith().getStatus(); + } + } + return effectiveResponseStatus; + } + + private boolean isAbortedWith(ClientRequestContextImpl requestContext) { + return requestContext != null && requestContext.getAbortedWith() != null; + } + private void setExistingEntity(Response abortedWith, ClientResponseContextImpl responseContext, RestClientRequestContext restClientRequestContext) throws IOException { Object value = abortedWith.getEntity();