diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/actuate/AbstractGatewayControllerEndpoint.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/actuate/AbstractGatewayControllerEndpoint.java index 2f97c8d4..dcdbffb6 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/actuate/AbstractGatewayControllerEndpoint.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/actuate/AbstractGatewayControllerEndpoint.java @@ -43,6 +43,7 @@ import org.springframework.context.ApplicationEventPublisherAware; import org.springframework.core.Ordered; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -156,6 +157,18 @@ public class AbstractGatewayControllerEndpoint implements ApplicationEventPublis else if (!unavailablePredicatesDefinitions.isEmpty()) { handleUnavailableDefinition(PredicateDefinition.class.getSimpleName(), unavailablePredicatesDefinitions); } + + validateRouteUri(routeDefinition.getUri()); + } + + private void validateRouteUri(URI uri) { + if (uri == null) { + handleError("The URI can not be empty"); + } + + if (!StringUtils.hasText(uri.getScheme())) { + handleError("The URI format [%s] is incorrect, scheme can not be empty".formatted(uri)); + } } private void handleUnavailableDefinition(String simpleName, Set unavailableDefinitions) { @@ -164,6 +177,11 @@ public class AbstractGatewayControllerEndpoint implements ApplicationEventPublis throw new ResponseStatusException(HttpStatus.BAD_REQUEST, errorMessage); } + private void handleError(String errorMessage) { + log.warn(errorMessage); + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, errorMessage); + } + private boolean isAvailable(FilterDefinition filterDefinition) { return GatewayFilters.stream() .anyMatch(gatewayFilterFactory -> filterDefinition.getName().equals(gatewayFilterFactory.name())); diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/actuate/GatewayControllerEndpointTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/actuate/GatewayControllerEndpointTests.java index 0a1094b9..3a90f412 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/actuate/GatewayControllerEndpointTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/actuate/GatewayControllerEndpointTests.java @@ -209,6 +209,30 @@ public class GatewayControllerEndpointTests { .isEqualTo("Invalid FilterDefinition: [NotExistingFilter]"); } + @Test + public void testPostRouteWithUriWithoutScheme() { + + RouteDefinition testRouteDefinition = new RouteDefinition(); + testRouteDefinition.setUri(URI.create("example.org")); + + testClient.post().uri("http://localhost:" + port + "/actuator/gateway/routes/no-scheme-test-route") + .accept(MediaType.APPLICATION_JSON).body(BodyInserters.fromValue(testRouteDefinition)).exchange() + .expectStatus().isBadRequest().expectBody().jsonPath("$.message") + .isEqualTo("The URI format [example.org] is incorrect, scheme can not be empty"); + } + + @Test + public void testPostRouteWithUri() { + + RouteDefinition testRouteDefinition = new RouteDefinition(); + testRouteDefinition.setUri(null); + + testClient.post().uri("http://localhost:" + port + "/actuator/gateway/routes/no-scheme-test-route") + .accept(MediaType.APPLICATION_JSON).body(BodyInserters.fromValue(testRouteDefinition)).exchange() + .expectStatus().isBadRequest().expectBody().jsonPath("$.message") + .isEqualTo("The URI can not be empty"); + } + @Test public void testPostRouteWithNotExistingPredicate() {