diff --git a/core-server/src/main/java/org/glassfish/jersey/server/ServerRuntime.java b/core-server/src/main/java/org/glassfish/jersey/server/ServerRuntime.java index d6eb5a6ba7..531e927a3b 100644 --- a/core-server/src/main/java/org/glassfish/jersey/server/ServerRuntime.java +++ b/core-server/src/main/java/org/glassfish/jersey/server/ServerRuntime.java @@ -130,6 +130,14 @@ public class ServerRuntime { /** Resolve relative URIs according to RFC7231 (not JAX-RS 2.0 compliant */ private final boolean rfc7231LocationHeaderRelativeUriResolution; + /** + * Cached value of configuration property + * {@link org.glassfish.jersey.server.ServerProperties#RESPONSE_SET_STATUS_OVER_SEND_ERROR}. + * If {@code true} method {@link ServerRuntime.CompletionCallbackRunner#onComplete(Throwable)} + * is used over {@link DefaultExceptionMapper#toResponse(Throwable)}. + */ + private final boolean configSetStatusOverSendError; + /** * Default exception mapper (@since 3.1.0 according to JAX-RS 3.1 spec) */ @@ -197,6 +205,9 @@ private ServerRuntime(final Stage requestProcessingRoo this.rfc7231LocationHeaderRelativeUriResolution = ServerProperties.getValue(configuration.getProperties(), ServerProperties.LOCATION_HEADER_RELATIVE_URI_RESOLUTION_RFC7231, Boolean.FALSE, Boolean.class); + + this.configSetStatusOverSendError = ServerProperties.getValue(configuration.getProperties(), + ServerProperties.RESPONSE_SET_STATUS_OVER_SEND_ERROR, false, Boolean.class); } /** @@ -452,15 +463,17 @@ public void process(final Throwable throwable) { if (!processResponseError(responseError)) { // Pass the exception to the container. - LOGGER.log(Level.WARNING, LocalizationMessages.ERROR_EXCEPTION_MAPPING_THROWN_TO_CONTAINER(), responseError); - try { request.getResponseWriter().failure(responseError); } finally { - defaultMapperResponse = processResponseWithDefaultExceptionMapper(responseError, request); - - // completionCallbackRunner.onComplete(responseError); is called from - // processResponseWithDefaultExceptionMapper + if (runtime.configSetStatusOverSendError) { + completionCallbackRunner.onComplete(responseError); + } else { + LOGGER.log(Level.WARNING, + LocalizationMessages.ERROR_EXCEPTION_MAPPING_THROWN_TO_CONTAINER(), + responseError); + defaultMapperResponse = processResponseWithDefaultExceptionMapper(responseError, request); + } } } diff --git a/tests/integration/servlet-tests/pom.xml b/tests/integration/servlet-tests/pom.xml index 23a13f8ec5..c42ca5d29b 100644 --- a/tests/integration/servlet-tests/pom.xml +++ b/tests/integration/servlet-tests/pom.xml @@ -48,6 +48,7 @@ org.glassfish.jersey.test-framework.providers jersey-test-framework-provider-external + test diff --git a/tests/integration/servlet-tests/src/main/java/org/glassfish/jersey/tests/integration/servlettests/PostProcessingErrorFilter.java b/tests/integration/servlet-tests/src/main/java/org/glassfish/jersey/tests/integration/servlettests/PostProcessingErrorFilter.java new file mode 100644 index 0000000000..856e2ef176 --- /dev/null +++ b/tests/integration/servlet-tests/src/main/java/org/glassfish/jersey/tests/integration/servlettests/PostProcessingErrorFilter.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2024 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.integration.servlettests; + +import jakarta.servlet.Filter; +import jakarta.servlet.FilterChain; +import jakarta.servlet.FilterConfig; +import jakarta.servlet.ServletException; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.ServletResponse; + +import java.io.IOException; + +import static org.glassfish.jersey.tests.integration.servlettests.PostProcessingErrorResource.ERROR_MESSAGE; + +public class PostProcessingErrorFilter implements Filter { + @Override + public void init(FilterConfig filterConfig) throws ServletException { + Filter.super.init(filterConfig); + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException { + + try { + chain.doFilter(request, response); + } catch (ServletException ex) { + //post-processing attempt + final Throwable orig = ex.getRootCause(); + if (orig.getMessage().equalsIgnoreCase(ERROR_MESSAGE)) { + response.getWriter().print(ERROR_MESSAGE); + response.getWriter().flush(); + } + } + } + + @Override + public void destroy() { + Filter.super.destroy(); + } +} diff --git a/tests/integration/servlet-tests/src/main/java/org/glassfish/jersey/tests/integration/servlettests/PostProcessingErrorResource.java b/tests/integration/servlet-tests/src/main/java/org/glassfish/jersey/tests/integration/servlettests/PostProcessingErrorResource.java new file mode 100644 index 0000000000..b9d345120d --- /dev/null +++ b/tests/integration/servlet-tests/src/main/java/org/glassfish/jersey/tests/integration/servlettests/PostProcessingErrorResource.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2024 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.integration.servlettests; + +import jakarta.servlet.http.HttpServlet; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.ProcessingException; +import jakarta.ws.rs.core.Response; + +@Path("postprocessing") +public class PostProcessingErrorResource extends HttpServlet { + + static final String ERROR_MESSAGE = "Must be post processed"; + @GET + public Response getException() { + throw new ProcessingException(ERROR_MESSAGE); + } + +} diff --git a/tests/integration/servlet-tests/src/main/webapp/WEB-INF/web.xml b/tests/integration/servlet-tests/src/main/webapp/WEB-INF/web.xml index 5d9d99e806..813b221a24 100644 --- a/tests/integration/servlet-tests/src/main/webapp/WEB-INF/web.xml +++ b/tests/integration/servlet-tests/src/main/webapp/WEB-INF/web.xml @@ -1,7 +1,7 @@ + + PostProcessFilter + org.glassfish.jersey.tests.integration.servlettests.PostProcessingErrorFilter + + + PostProcessServlet + org.glassfish.jersey.servlet.ServletContainer + + jersey.config.server.provider.classnames + org.glassfish.jersey.tests.integration.servlettests.PostProcessingErrorResource + + + jersey.config.server.response.setStatusOverSendError + true + + 1 + + + PostProcessServlet + /postProcess/* + + + PostProcessFilter + /postProcess/* + diff --git a/tests/integration/servlet-tests/src/test/java/org/glassfish/jersey/tests/integration/servlettests/PostProcesingITCase.java b/tests/integration/servlet-tests/src/test/java/org/glassfish/jersey/tests/integration/servlettests/PostProcesingITCase.java new file mode 100644 index 0000000000..dbab31520b --- /dev/null +++ b/tests/integration/servlet-tests/src/test/java/org/glassfish/jersey/tests/integration/servlettests/PostProcesingITCase.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2024 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.integration.servlettests; + +import jakarta.ws.rs.core.Application; +import jakarta.ws.rs.core.Response; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.server.ServerProperties; +import org.glassfish.jersey.test.JerseyTest; +import org.glassfish.jersey.test.external.ExternalTestContainerFactory; +import org.glassfish.jersey.test.spi.TestContainerException; +import org.glassfish.jersey.test.spi.TestContainerFactory; +import org.junit.jupiter.api.Test; + +import java.util.Locale; + +import static org.glassfish.jersey.tests.integration.servlettests.PostProcessingErrorResource.ERROR_MESSAGE; +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class PostProcesingITCase extends JerseyTest { + + @Override + protected Application configure() { + // dummy resource config + return new ResourceConfig(); + } + + @Override + protected TestContainerFactory getTestContainerFactory() throws TestContainerException { + return new ExternalTestContainerFactory(); + } + + @Test + public void testPostProcessingLocale() { + final Response response = target() + .path("postProcess/postprocessing") + .request().get(); + assertEquals(ERROR_MESSAGE, response.readEntity(String.class)); + } + +}