Allowing sending Status over sending error Signed-off-by: Maxim Nesen <maxim.nesen@oracle.com>
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 d6eb5a6..531e927 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
@@ -131,6 +131,14 @@ 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) */ private static final ExceptionMapper<Throwable> DEFAULT_EXCEPTION_MAPPER = new DefaultExceptionMapper(); @@ -197,6 +205,9 @@ 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 @@ 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 23a13f8..c42ca5d 100644 --- a/tests/integration/servlet-tests/pom.xml +++ b/tests/integration/servlet-tests/pom.xml
@@ -48,6 +48,7 @@ <dependency> <groupId>org.glassfish.jersey.test-framework.providers</groupId> <artifactId>jersey-test-framework-provider-external</artifactId> + <scope>test</scope> </dependency> </dependencies>
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 0000000..856e2ef --- /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 0000000..b9d3451 --- /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 5d9d99e..813b221 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 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- - Copyright (c) 2010, 2018 Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2010, 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 @@ -157,4 +157,31 @@ <filter-name>custom404</filter-name> <url-pattern>/custom404/*</url-pattern> </filter-mapping> + + <!-- post process errors (40*, 50*) --> + <filter> + <filter-name>PostProcessFilter</filter-name> + <filter-class>org.glassfish.jersey.tests.integration.servlettests.PostProcessingErrorFilter</filter-class> + </filter> + <servlet> + <servlet-name>PostProcessServlet</servlet-name> + <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class> + <init-param> + <param-name>jersey.config.server.provider.classnames</param-name> + <param-value>org.glassfish.jersey.tests.integration.servlettests.PostProcessingErrorResource</param-value> + </init-param> + <init-param> + <param-name>jersey.config.server.response.setStatusOverSendError</param-name> + <param-value>true</param-value> + </init-param> + <load-on-startup>1</load-on-startup> + </servlet> + <servlet-mapping> + <servlet-name>PostProcessServlet</servlet-name> + <url-pattern>/postProcess/*</url-pattern> + </servlet-mapping> + <filter-mapping> + <filter-name>PostProcessFilter</filter-name> + <url-pattern>/postProcess/*</url-pattern> + </filter-mapping> </web-app>
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 0000000..dbab315 --- /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)); + } + +}