From fb651e210687a8f0a6e9db0acdbc0f3a11a2c48d Mon Sep 17 00:00:00 2001 From: Jorge Bescos Gascon Date: Mon, 11 Apr 2022 11:20:49 +0200 Subject: [PATCH] Blocked thread if WebApplicationException is reused. #4097 Signed-off-by: Jorge Bescos Gascon --- .../servlet/internal/ResponseWriter.java | 3 +- .../AbstractJavaResourceMethodDispatcher.java | 16 ++++- .../server/internal/localization.properties | 3 +- .../tests/e2e/server/Issue4097Test.java | 68 +++++++++++++++++++ 4 files changed, 85 insertions(+), 5 deletions(-) create mode 100644 tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/Issue4097Test.java diff --git a/containers/jersey-servlet-core/src/main/java/org/glassfish/jersey/servlet/internal/ResponseWriter.java b/containers/jersey-servlet-core/src/main/java/org/glassfish/jersey/servlet/internal/ResponseWriter.java index 451e912d8d..e7285ccb7b 100644 --- a/containers/jersey-servlet-core/src/main/java/org/glassfish/jersey/servlet/internal/ResponseWriter.java +++ b/containers/jersey-servlet-core/src/main/java/org/glassfish/jersey/servlet/internal/ResponseWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2019 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2022 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at @@ -233,6 +233,7 @@ public void failure(final Throwable error) { } } finally { requestTimeoutHandler.close(); + responseContext.completeExceptionally(error); rethrow(error); } } diff --git a/core-server/src/main/java/org/glassfish/jersey/server/model/internal/AbstractJavaResourceMethodDispatcher.java b/core-server/src/main/java/org/glassfish/jersey/server/model/internal/AbstractJavaResourceMethodDispatcher.java index 5f8154dd73..853e717846 100644 --- a/core-server/src/main/java/org/glassfish/jersey/server/model/internal/AbstractJavaResourceMethodDispatcher.java +++ b/core-server/src/main/java/org/glassfish/jersey/server/model/internal/AbstractJavaResourceMethodDispatcher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2019 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2022 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at @@ -25,13 +25,15 @@ import java.util.concurrent.CompletionStage; import java.util.concurrent.ExecutionException; +import javax.validation.ValidationException; import javax.ws.rs.ProcessingException; import javax.ws.rs.WebApplicationException; +import javax.ws.rs.client.ResponseProcessingException; import javax.ws.rs.core.Response; import javax.ws.rs.core.SecurityContext; -import javax.validation.ValidationException; - +import org.glassfish.jersey.message.internal.OutboundJaxrsResponse; +import org.glassfish.jersey.message.internal.OutboundMessageContext; import org.glassfish.jersey.message.internal.TracingLogger; import org.glassfish.jersey.server.ContainerRequest; import org.glassfish.jersey.server.SubjectSecurityContext; @@ -77,6 +79,14 @@ public final Response dispatch(Object resource, ContainerRequest request) throws Response response = null; try { response = doDispatch(resource, request); + if (response instanceof OutboundJaxrsResponse) { + OutboundJaxrsResponse responseImpl = (OutboundJaxrsResponse) response; + OutboundMessageContext context = responseImpl.getContext(); + if (context.isCommitted()) { + // Response was already committed. This response is being reused more than 1 time. + throw new ResponseProcessingException(response, LocalizationMessages.ERROR_RESPONSE_ALREADY_COMMITED()); + } + } } finally { TracingLogger.getInstance(request).log(ServerTraceEvent.DISPATCH_RESPONSE, response); } diff --git a/core-server/src/main/resources/org/glassfish/jersey/server/internal/localization.properties b/core-server/src/main/resources/org/glassfish/jersey/server/internal/localization.properties index 4311fee54f..7dc07a00a4 100644 --- a/core-server/src/main/resources/org/glassfish/jersey/server/internal/localization.properties +++ b/core-server/src/main/resources/org/glassfish/jersey/server/internal/localization.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2012, 2020 Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2012, 2022 Oracle and/or its affiliates. All rights reserved. # # This program and the accompanying materials are made available under the # terms of the Eclipse Public License v. 2.0, which is available at @@ -71,6 +71,7 @@ error.resources.cannot.merge=Resources do not have the same path and cannot be m error.request.abort.in.response.phase=The request cannot be aborted as it is already in the response processing phase. error.request.set.entity.stream.in.response.phase=The entity stream cannot be set in the request as it is already in the response processing phase. error.request.set.security.context.in.response.phase=The security context cannot be set in the request as it is already in the response processing phase. +error.response.already.commited=Response was already committed. This response is being reused more than 1 time. error.scanning.class.not.found=A class file of the class name, {0}, is identified but the class could not be found. error.sub.resource.locator.more.resources=Sub resource locator returned {0} in the resource model. Exactly one resource must be returned. error.suspending.chunked.output.response=Attempt to suspend a client connection associated with a chunked output has failed in the underlying container. diff --git a/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/Issue4097Test.java b/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/Issue4097Test.java new file mode 100644 index 0000000000..696e3049fc --- /dev/null +++ b/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/Issue4097Test.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2022 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.tests.e2e.server; + +import static org.junit.Assert.assertEquals; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.client.WebTarget; +import javax.ws.rs.core.Application; +import javax.ws.rs.core.Response; + +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.test.JerseyTest; +import org.glassfish.jersey.test.jdkhttp.JdkHttpServerTestContainerFactory; +import org.glassfish.jersey.test.spi.TestContainerException; +import org.glassfish.jersey.test.spi.TestContainerFactory; +import org.junit.Test; + +public class Issue4097Test extends JerseyTest { + + @Override + protected Application configure() { + return new ResourceConfig(Issue4097Resource.class); + } + + @Override + protected TestContainerFactory getTestContainerFactory() throws TestContainerException { + return new JdkHttpServerTestContainerFactory(); + } + + @Test + public void reuseResponse() throws InterruptedException { + WebTarget webTarget = target("/issue4097/reuseResponse"); + assertEquals(410, webTarget.request().get().getStatus()); + assertEquals(500, webTarget.request().get().getStatus()); + assertEquals(500, webTarget.request().get().getStatus()); + } + + @Path("/issue4097") + public static class Issue4097Resource { + + private static final Response RESPONSE = + Response.status(410).entity("test").build(); + + @GET + @Path("/reuseResponse") + public Response reuseResponse() { + // returning the same response is obviously wrong + return RESPONSE; + } + } + +}