diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/NettyWriteResponseFilter.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/NettyWriteResponseFilter.java index 386678f1..b5b836f8 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/NettyWriteResponseFilter.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/NettyWriteResponseFilter.java @@ -130,10 +130,15 @@ public class NettyWriteResponseFilter implements GlobalFilter, Ordered { } // TODO: use framework if possible - // TODO: port to WebClientWriteResponseFilter private boolean isStreamingMediaType(@Nullable MediaType contentType) { - return (contentType != null && this.streamingMediaTypes.stream() - .anyMatch(contentType::isCompatibleWith)); + if (contentType != null) { + for (int i = 0; i < streamingMediaTypes.size(); i++) { + if (streamingMediaTypes.get(i).isCompatibleWith(contentType)) { + return true; + } + } + } + return false; } } diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/WebsocketRoutingFilter.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/WebsocketRoutingFilter.java index e5b2f662..ef74a839 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/WebsocketRoutingFilter.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/WebsocketRoutingFilter.java @@ -21,7 +21,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; -import java.util.stream.Collectors; +import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -31,6 +31,7 @@ import org.springframework.beans.factory.ObjectProvider; import org.springframework.cloud.gateway.filter.headers.HttpHeadersFilter; import org.springframework.core.Ordered; import org.springframework.http.HttpHeaders; +import org.springframework.util.StringUtils; import org.springframework.web.reactive.socket.WebSocketHandler; import org.springframework.web.reactive.socket.WebSocketMessage; import org.springframework.web.reactive.socket.WebSocketSession; @@ -45,7 +46,6 @@ import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.P import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.containsEncodedParts; import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.isAlreadyRouted; import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.setAlreadyRouted; -import static org.springframework.util.StringUtils.commaDelimitedListToStringArray; /** * @author Spencer Gibb @@ -105,17 +105,26 @@ public class WebsocketRoutingFilter implements GlobalFilter, Ordered { HttpHeaders headers = exchange.getRequest().getHeaders(); HttpHeaders filtered = filterRequest(getHeadersFilters(), exchange); - List protocols = headers.get(SEC_WEBSOCKET_PROTOCOL); - if (protocols != null) { - protocols = headers.get(SEC_WEBSOCKET_PROTOCOL).stream().flatMap( - header -> Arrays.stream(commaDelimitedListToStringArray(header))) - .map(String::trim).collect(Collectors.toList()); - } + List protocols = getProtocols(headers); return this.webSocketService.handleRequest(exchange, new ProxyWebSocketHandler( requestUrl, this.webSocketClient, filtered, protocols)); } + /* for testing */ List getProtocols(HttpHeaders headers) { + List protocols = headers.get(SEC_WEBSOCKET_PROTOCOL); + if (protocols != null) { + ArrayList updatedProtocols = new ArrayList<>(); + for (int i = 0; i < protocols.size(); i++) { + String protocol = protocols.get(i); + updatedProtocols.addAll( + Arrays.asList(StringUtils.tokenizeToStringArray(protocol, ","))); + } + protocols = updatedProtocols; + } + return protocols; + } + /* for testing */ List getHeadersFilters() { if (this.headersFilters == null) { this.headersFilters = this.headersFiltersProvider @@ -138,11 +147,11 @@ public class WebsocketRoutingFilter implements GlobalFilter, Ordered { headersFilters.add((headers, exchange) -> { HttpHeaders filtered = new HttpHeaders(); - headers.entrySet().stream() - .filter(entry -> !entry.getKey().toLowerCase() - .startsWith("sec-websocket")) - .forEach(header -> filtered.addAll(header.getKey(), - header.getValue())); + for (Map.Entry> entry : headers.entrySet()) { + if (!entry.getKey().toLowerCase().startsWith("sec-websocket")) { + filtered.addAll(entry.getKey(), entry.getValue()); + } + } return filtered; }); } diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/DedupeResponseHeaderGatewayFilterFactory.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/DedupeResponseHeaderGatewayFilterFactory.java index ec2443fe..7fd92f7d 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/DedupeResponseHeaderGatewayFilterFactory.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/DedupeResponseHeaderGatewayFilterFactory.java @@ -16,9 +16,10 @@ package org.springframework.cloud.gateway.filter.factory; +import java.util.ArrayList; import java.util.Arrays; +import java.util.LinkedHashSet; import java.util.List; -import java.util.stream.Collectors; import reactor.core.publisher.Mono; @@ -146,7 +147,7 @@ public class DedupeResponseHeaderGatewayFilterFactory extends headers.set(name, values.get(values.size() - 1)); break; case RETAIN_UNIQUE: - headers.put(name, values.stream().distinct().collect(Collectors.toList())); + headers.put(name, new ArrayList<>(new LinkedHashSet<>(values))); break; default: break; diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/RetryGatewayFilterFactory.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/RetryGatewayFilterFactory.java index 6e79e358..44181dad 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/RetryGatewayFilterFactory.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/RetryGatewayFilterFactory.java @@ -87,8 +87,13 @@ public class RetryGatewayFilterFactory // null status code might mean a network exception? if (!retryableStatusCode && statusCode != null) { // try the series - retryableStatusCode = retryConfig.getSeries().stream() - .anyMatch(series -> statusCode.series().equals(series)); + retryableStatusCode = false; + for (int i = 0; i < retryConfig.getSeries().size(); i++) { + if (statusCode.series().equals(retryConfig.getSeries().get(i))) { + retryableStatusCode = true; + break; + } + } } final boolean finalRetryableStatusCode = retryableStatusCode; diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/RewriteResponseHeaderGatewayFilterFactory.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/RewriteResponseHeaderGatewayFilterFactory.java index a74cbdaa..77ab9b4b 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/RewriteResponseHeaderGatewayFilterFactory.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/RewriteResponseHeaderGatewayFilterFactory.java @@ -16,9 +16,9 @@ package org.springframework.cloud.gateway.filter.factory; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.stream.Collectors; import reactor.core.publisher.Mono; @@ -88,9 +88,13 @@ public class RewriteResponseHeaderGatewayFilterFactory extends } protected List rewriteHeaders(Config config, List headers) { - return headers.stream() - .map(val -> rewrite(val, config.getRegexp(), config.getReplacement())) - .collect(Collectors.toList()); + ArrayList rewrittenHeaders = new ArrayList<>(); + for (int i = 0; i < headers.size(); i++) { + String rewriten = rewrite(headers.get(i), config.getRegexp(), + config.getReplacement()); + rewrittenHeaders.add(rewriten); + } + return rewrittenHeaders; } String rewrite(String value, String regexp, String replacement) { diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/StripPrefixGatewayFilterFactory.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/StripPrefixGatewayFilterFactory.java index aea6f5b9..64b6aa20 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/StripPrefixGatewayFilterFactory.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/StripPrefixGatewayFilterFactory.java @@ -18,7 +18,6 @@ package org.springframework.cloud.gateway.filter.factory; import java.util.Arrays; import java.util.List; -import java.util.stream.Collectors; import reactor.core.publisher.Mono; @@ -64,11 +63,25 @@ public class StripPrefixGatewayFilterFactory ServerHttpRequest request = exchange.getRequest(); addOriginalRequestUrl(exchange, request.getURI()); String path = request.getURI().getRawPath(); - String newPath = "/" - + Arrays.stream(StringUtils.tokenizeToStringArray(path, "/")) - .skip(config.parts).collect(Collectors.joining("/")); - newPath += (newPath.length() > 1 && path.endsWith("/") ? "/" : ""); - ServerHttpRequest newRequest = request.mutate().path(newPath).build(); + String[] originalParts = StringUtils.tokenizeToStringArray(path, "/"); + + // all new paths start with / + StringBuilder newPath = new StringBuilder("/"); + for (int i = 0; i < originalParts.length; i++) { + if (i >= config.getParts()) { + // only append slash if this is the second part or greater + if (newPath.length() > 1) { + newPath.append('/'); + } + newPath.append(originalParts[i]); + } + } + if (newPath.length() > 1 && path.endsWith("/")) { + newPath.append('/'); + } + + ServerHttpRequest newRequest = request.mutate().path(newPath.toString()) + .build(); exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, newRequest.getURI()); diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/headers/ForwardedHeadersFilter.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/headers/ForwardedHeadersFilter.java index c40779f4..6f24c512 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/headers/ForwardedHeadersFilter.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/headers/ForwardedHeadersFilter.java @@ -98,9 +98,11 @@ public class ForwardedHeadersFilter implements HttpHeadersFilter, Ordered { HttpHeaders updated = new HttpHeaders(); // copy all headers except Forwarded - original.entrySet().stream().filter( - entry -> !entry.getKey().toLowerCase().equalsIgnoreCase(FORWARDED_HEADER)) - .forEach(entry -> updated.addAll(entry.getKey(), entry.getValue())); + for (Map.Entry> entry : original.entrySet()) { + if (!entry.getKey().equalsIgnoreCase(FORWARDED_HEADER)) { + updated.addAll(entry.getKey(), entry.getValue()); + } + } List forwardeds = parse(original.get(FORWARDED_HEADER)); diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/headers/HttpHeadersFilter.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/headers/HttpHeadersFilter.java index 0fadfacc..ada3cc85 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/headers/HttpHeadersFilter.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/headers/HttpHeadersFilter.java @@ -31,19 +31,18 @@ public interface HttpHeadersFilter { static HttpHeaders filter(List filters, HttpHeaders input, ServerWebExchange exchange, Type type) { - HttpHeaders response = input; if (filters != null) { - HttpHeaders reduce = filters.stream() - .filter(headersFilter -> headersFilter.supports(type)).reduce(input, - (headers, filter) -> filter.filter(headers, exchange), - (httpHeaders, httpHeaders2) -> { - httpHeaders.addAll(httpHeaders2); - return httpHeaders; - }); - return reduce; + HttpHeaders filtered = input; + for (int i = 0; i < filters.size(); i++) { + HttpHeadersFilter filter = filters.get(i); + if (filter.supports(type)) { + filtered = filter.filter(filtered, exchange); + } + } + return filtered; } - return response; + return input; } /** diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/headers/RemoveHopByHopHeadersFilter.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/headers/RemoveHopByHopHeadersFilter.java index ce0f465b..e68159c4 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/headers/RemoveHopByHopHeadersFilter.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/headers/RemoveHopByHopHeadersFilter.java @@ -18,6 +18,8 @@ package org.springframework.cloud.gateway.filter.headers; import java.util.Arrays; import java.util.HashSet; +import java.util.List; +import java.util.Map; import java.util.Set; import org.springframework.boot.context.properties.ConfigurationProperties; @@ -66,9 +68,11 @@ public class RemoveHopByHopHeadersFilter implements HttpHeadersFilter, Ordered { public HttpHeaders filter(HttpHeaders input, ServerWebExchange exchange) { HttpHeaders filtered = new HttpHeaders(); - input.entrySet().stream() - .filter(entry -> !this.headers.contains(entry.getKey().toLowerCase())) - .forEach(entry -> filtered.addAll(entry.getKey(), entry.getValue())); + for (Map.Entry> entry : input.entrySet()) { + if (!this.headers.contains(entry.getKey().toLowerCase())) { + filtered.addAll(entry.getKey(), entry.getValue()); + } + } return filtered; } diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/headers/XForwardedHeadersFilter.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/headers/XForwardedHeadersFilter.java index 7906d24e..352789ae 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/headers/XForwardedHeadersFilter.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/headers/XForwardedHeadersFilter.java @@ -19,6 +19,7 @@ package org.springframework.cloud.gateway.filter.headers; import java.net.URI; import java.util.LinkedHashSet; import java.util.List; +import java.util.Map; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.core.Ordered; @@ -201,8 +202,9 @@ public class XForwardedHeadersFilter implements HttpHeadersFilter, Ordered { HttpHeaders original = input; HttpHeaders updated = new HttpHeaders(); - original.entrySet().stream() - .forEach(entry -> updated.addAll(entry.getKey(), entry.getValue())); + for (Map.Entry> entry : original.entrySet()) { + updated.addAll(entry.getKey(), entry.getValue()); + } if (isForEnabled() && request.getRemoteAddress() != null && request.getRemoteAddress().getAddress() != null) { @@ -229,7 +231,7 @@ public class XForwardedHeadersFilter implements HttpHeadersFilter, Ordered { if (originalUris != null && requestUri != null) { - originalUris.stream().forEach(originalUri -> { + originalUris.forEach(originalUri -> { if (originalUri != null && originalUri.getPath() != null) { String prefix = originalUri.getPath(); diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/handler/predicate/HeaderRoutePredicateFactory.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/handler/predicate/HeaderRoutePredicateFactory.java index c774a26d..697c0c2f 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/handler/predicate/HeaderRoutePredicateFactory.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/handler/predicate/HeaderRoutePredicateFactory.java @@ -67,8 +67,13 @@ public class HeaderRoutePredicateFactory // values is now guaranteed to not be empty if (hasRegex) { // check if a header value matches - return values.stream() - .anyMatch(value -> value.matches(config.regexp)); + for (int i = 0; i < values.size(); i++) { + String value = values.get(i); + if (value.matches(config.regexp)) { + return true; + } + } + return false; } // there is a value and since regexp is empty, we only check existence. diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/handler/predicate/HostRoutePredicateFactory.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/handler/predicate/HostRoutePredicateFactory.java index 2212ef2d..6950907a 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/handler/predicate/HostRoutePredicateFactory.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/handler/predicate/HostRoutePredicateFactory.java @@ -20,7 +20,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.Optional; import java.util.function.Predicate; import org.springframework.cloud.gateway.support.ServerWebExchangeUtils; @@ -63,12 +62,18 @@ public class HostRoutePredicateFactory @Override public boolean test(ServerWebExchange exchange) { String host = exchange.getRequest().getHeaders().getFirst("Host"); - Optional optionalPattern = config.getPatterns().stream() - .filter(pattern -> pathMatcher.match(pattern, host)).findFirst(); + String match = null; + for (int i = 0; i < config.getPatterns().size(); i++) { + String pattern = config.getPatterns().get(i); + if (pathMatcher.match(pattern, host)) { + match = pattern; + break; + } + } - if (optionalPattern.isPresent()) { + if (match != null) { Map variables = pathMatcher - .extractUriTemplateVariables(optionalPattern.get(), host); + .extractUriTemplateVariables(match, host); ServerWebExchangeUtils.putUriTemplateVariables(exchange, variables); return true; } diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/handler/predicate/PathRoutePredicateFactory.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/handler/predicate/PathRoutePredicateFactory.java index 645cb7bc..5618c397 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/handler/predicate/PathRoutePredicateFactory.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/handler/predicate/PathRoutePredicateFactory.java @@ -19,7 +19,6 @@ package org.springframework.cloud.gateway.handler.predicate; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.Optional; import java.util.function.Predicate; import org.apache.commons.logging.Log; @@ -93,13 +92,18 @@ public class PathRoutePredicateFactory PathContainer path = parsePath( exchange.getRequest().getURI().getRawPath()); - Optional optionalPathPattern = pathPatterns.stream() - .filter(pattern -> pattern.matches(path)).findFirst(); + PathPattern match = null; + for (int i = 0; i < pathPatterns.size(); i++) { + PathPattern pathPattern = pathPatterns.get(i); + if (pathPattern.matches(path)) { + match = pathPattern; + break; + } + } - if (optionalPathPattern.isPresent()) { - PathPattern pathPattern = optionalPathPattern.get(); - traceMatch("Pattern", pathPattern.getPatternString(), path, true); - PathMatchInfo pathMatchInfo = pathPattern.matchAndExtract(path); + if (match != null) { + traceMatch("Pattern", match.getPatternString(), path, true); + PathMatchInfo pathMatchInfo = match.matchAndExtract(path); putUriTemplateVariables(exchange, pathMatchInfo.getUriVariables()); return true; } diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/WebsocketRoutingFilterTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/WebsocketRoutingFilterTests.java index d9b5b2fb..6044f1dc 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/WebsocketRoutingFilterTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/WebsocketRoutingFilterTests.java @@ -18,6 +18,7 @@ package org.springframework.cloud.gateway.filter; import java.net.URI; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import org.junit.Test; @@ -35,6 +36,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import static org.springframework.cloud.gateway.filter.WebsocketRoutingFilter.SEC_WEBSOCKET_PROTOCOL; import static org.springframework.cloud.gateway.filter.WebsocketRoutingFilter.changeSchemeIfIsWebSocketUpgrade; import static org.springframework.cloud.gateway.filter.WebsocketRoutingFilter.convertHttpToWs; import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR; @@ -44,6 +46,21 @@ import static org.springframework.http.HttpHeaders.UPGRADE; public class WebsocketRoutingFilterTests { + @Test + @SuppressWarnings("unchecked") + public void testProtocolParsing() { + ObjectProvider> headersFilters = mock( + ObjectProvider.class); + WebsocketRoutingFilter filter = new WebsocketRoutingFilter( + mock(WebSocketClient.class), mock(WebSocketService.class), + headersFilters); + + HttpHeaders headers = new HttpHeaders(); + headers.put(SEC_WEBSOCKET_PROTOCOL, Arrays.asList(" p1,p2", "p3 , p4 ")); + List protocols = filter.getProtocols(headers); + assertThat(protocols).containsExactly("p1", "p2", "p3", "p4"); + } + @Test public void testConvertHttpToWs() { assertThat(convertHttpToWs("http")).isEqualTo("ws"); diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/RetryGatewayFilterFactoryIntegrationTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/RetryGatewayFilterFactoryIntegrationTests.java index 69a51265..d94f389b 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/RetryGatewayFilterFactoryIntegrationTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/RetryGatewayFilterFactoryIntegrationTests.java @@ -197,6 +197,13 @@ public class RetryGatewayFilterFactoryIntegrationTests extends BaseWebClientTest }); } + @Test + public void retryFilterSeries() { + testClient.get().uri("/retry?key=series&failStatus=404") + .header(HttpHeaders.HOST, "www.retryseries.org").exchange().expectStatus() + .isOk().expectBody(String.class).isEqualTo("3"); + } + @Test public void toStringFormat() { RetryConfig config = new RetryConfig(); @@ -251,7 +258,7 @@ public class RetryGatewayFilterFactoryIntegrationTests extends BaseWebClientTest @RequestParam(name = "count", defaultValue = "3") int count, @RequestParam("expectedbody") String expectedbody, @RequestBody String body) { - ResponseEntity response = retry(key, count); + ResponseEntity response = retry(key, count, null); if (!expectedbody.equals(body)) { AtomicInteger num = getCount(key); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) @@ -263,14 +270,19 @@ public class RetryGatewayFilterFactoryIntegrationTests extends BaseWebClientTest @RequestMapping("/httpbin/retry") public ResponseEntity retry(@RequestParam("key") String key, - @RequestParam(name = "count", defaultValue = "3") int count) { + @RequestParam(name = "count", defaultValue = "3") int count, + @RequestParam(name = "failStatus", required = false) Integer failStatus) { AtomicInteger num = getCount(key); int i = num.incrementAndGet(); log.warn("Retry count: " + i); String body = String.valueOf(i); if (i < count) { - return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) - .header("X-Retry-Count", body).body("temporarily broken"); + HttpStatus httpStatus = HttpStatus.INTERNAL_SERVER_ERROR; + if (failStatus != null) { + httpStatus = HttpStatus.resolve(failStatus); + } + return ResponseEntity.status(httpStatus).header("X-Retry-Count", body) + .body("temporarily broken"); } return ResponseEntity.status(HttpStatus.OK).header("X-Retry-Count", body) .body(body); @@ -288,6 +300,11 @@ public class RetryGatewayFilterFactoryIntegrationTests extends BaseWebClientTest .retry(config -> config.setRetries(2) .setMethods(HttpMethod.POST, HttpMethod.GET))) .uri(uri)) + .route("retry_series", r -> r.host("**.retryseries.org") + .filters(f -> f.prefixPath("/httpbin") + .retry(config -> config.setRetries(2) + .setSeries(HttpStatus.Series.CLIENT_ERROR))) + .uri(uri)) .route("retry_only_get", r -> r.host("**.retry-only-get.org") .filters(f -> f.prefixPath("/httpbin") .retry(config -> config.setRetries(2)