Merge pull request #682 from vuilleumierc/GSBAB-281-18n-service-exception

Handle unsupported language service exception
This commit is contained in:
Gabriel Roldan 2025-07-10 17:47:58 -03:00 committed by GitHub
commit ba0ef2c323
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 111 additions and 19 deletions

View File

@ -62,13 +62,13 @@ public class StatusCodeWmsExceptionHandler extends WMSServiceExceptionHandler {
@Override
public void handleServiceException(ServiceException exception, Request request) {
setStausCode(exception, request);
setStatusCode(exception, request);
super.handleServiceException(exception, request);
}
private void setStausCode(ServiceException exception, Request request) {
protected void setStatusCode(ServiceException exception, Request request) {
if (shallSetStatus(request)) {
HttpStatus status = determineStatucCode(exception);
HttpStatus status = determineStatusCode(exception);
HttpServletResponse response = request.getHttpResponse();
response.setStatus(status.value());
}
@ -83,22 +83,31 @@ public class StatusCodeWmsExceptionHandler extends WMSServiceExceptionHandler {
return propertyResolver.getProperty(ENABLED_PROPERTY, Boolean.class, Boolean.FALSE);
}
private HttpStatus determineStatucCode(ServiceException exception) {
// RenderedImageMapOutputFormat does not set a ServiceException code in case of
// rendering timeout, so check the message:
if (exception.getMessage() != null
&& exception.getMessage().startsWith("This request used more time than allowed")) {
/*
* The 503 (Service Unavailable) status code indicates that the server is
* currently unable to handle the request due to a temporary overload or
* scheduled maintenance, which will likely be alleviated after some delay.
*/
return HttpStatus.SERVICE_UNAVAILABLE;
private HttpStatus determineStatusCode(ServiceException exception) {
final String code = exception.getCode();
final String message = exception.getMessage();
if (code == null && message != null) {
// Some ServiceException do not have code, so check the message instead
if (message.startsWith("This request used more time than allowed")) {
/*
* RenderedImageMapOutputFormat (rendering timeout)
* The 503 (Service Unavailable) status code indicates that the server is
* currently unable to handle the request due to a temporary overload or
* scheduled maintenance, which will likely be alleviated after some delay.
*/
return HttpStatus.SERVICE_UNAVAILABLE;
} else if (message.contains("Content has been requested in one of the following languages:")) {
// Capabilities_1_3_0_Response (the language requested with the query param ACCEPTLANGUAGES is not
// supported)
return HttpStatus.BAD_REQUEST;
}
} else if (code != null) {
return switch (code) {
case MISSING_PARAMETER_VALUE, INVALID_PARAMETER_VALUE, "InvalidCRS" -> HttpStatus.BAD_REQUEST;
case SERVICE_UNAVAILABLE, MAX_MEMORY_EXCEEDED -> HttpStatus.SERVICE_UNAVAILABLE;
default -> HttpStatus.INTERNAL_SERVER_ERROR;
};
}
return switch (exception.getCode()) {
case MISSING_PARAMETER_VALUE, INVALID_PARAMETER_VALUE, "InvalidCRS" -> HttpStatus.BAD_REQUEST;
case SERVICE_UNAVAILABLE, MAX_MEMORY_EXCEEDED -> HttpStatus.SERVICE_UNAVAILABLE;
default -> HttpStatus.INTERNAL_SERVER_ERROR;
};
return HttpStatus.INTERNAL_SERVER_ERROR;
}
}

View File

@ -0,0 +1,83 @@
/* (c) 2025 Open Source Geospatial Foundation - all rights reserved
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.cloud.wms.app;
import static org.geoserver.platform.ServiceException.INVALID_PARAMETER_VALUE;
import static org.geoserver.platform.ServiceException.MAX_MEMORY_EXCEEDED;
import static org.geoserver.platform.ServiceException.MISSING_PARAMETER_VALUE;
import static org.geoserver.platform.ServiceException.SERVICE_UNAVAILABLE;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.List;
import java.util.stream.Stream;
import javax.servlet.http.HttpServletResponse;
import org.geoserver.config.GeoServer;
import org.geoserver.ows.Request;
import org.geoserver.platform.ServiceException;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.springframework.core.env.PropertyResolver;
import org.springframework.http.HttpStatus;
public class StatusCodeWmsExceptionHandlerTest {
private StatusCodeWmsExceptionHandler handler;
private PropertyResolver propertyResolver = mock(PropertyResolver.class);
private GeoServer geoServer = mock(GeoServer.class);
@BeforeEach
void setUp() {
when(propertyResolver.getProperty("geoserver.wms.exceptions.w3cstatus", Boolean.class, Boolean.FALSE))
.thenReturn(true);
handler = new StatusCodeWmsExceptionHandler(List.of(), geoServer, propertyResolver);
}
@ParameterizedTest
@MethodSource("exceptionCodeToHttpStatus")
void setStatusCodeWithExceptionCodeTest(String exceptionCode, HttpStatus expectedStatus) {
ServiceException serviceException = new ServiceException("Some message", exceptionCode);
Request request = mock(Request.class);
HttpServletResponse response = mock(HttpServletResponse.class);
when(request.getHttpResponse()).thenReturn(response);
handler.setStatusCode(serviceException, request);
verify(response).setStatus(expectedStatus.value());
}
private static Stream<Arguments> exceptionCodeToHttpStatus() {
return Stream.of(
Arguments.of(MISSING_PARAMETER_VALUE, HttpStatus.BAD_REQUEST),
Arguments.of(INVALID_PARAMETER_VALUE, HttpStatus.BAD_REQUEST),
Arguments.of("InvalidCRS", HttpStatus.BAD_REQUEST),
Arguments.of(SERVICE_UNAVAILABLE, HttpStatus.SERVICE_UNAVAILABLE),
Arguments.of(MAX_MEMORY_EXCEEDED, HttpStatus.SERVICE_UNAVAILABLE),
Arguments.of("SomeUnknownCode", HttpStatus.INTERNAL_SERVER_ERROR));
}
@ParameterizedTest
@MethodSource("exceptionMessageToHttpStatus")
void setStatusCodeWithExceptionMessageTest(String message, HttpStatus expectedStatus) {
ServiceException exception = new ServiceException(message);
Request request = mock(Request.class);
HttpServletResponse response = mock(HttpServletResponse.class);
when(request.getHttpResponse()).thenReturn(response);
handler.setStatusCode(exception, request);
verify(response).setStatus(expectedStatus.value());
}
private static Stream<Arguments> exceptionMessageToHttpStatus() {
return Stream.of(
Arguments.of("This request used more time than allowed", HttpStatus.SERVICE_UNAVAILABLE),
Arguments.of("Content has been requested in one of the following languages:", HttpStatus.BAD_REQUEST),
Arguments.of("Unknown message", HttpStatus.INTERNAL_SERVER_ERROR));
}
}