diff --git a/discoverable-client/src/main/resources/application.yml b/discoverable-client/src/main/resources/application.yml index fcc2d4bbe0..f9b13442da 100644 --- a/discoverable-client/src/main/resources/application.yml +++ b/discoverable-client/src/main/resources/application.yml @@ -129,7 +129,10 @@ apiml: trustStore: ${server.ssl.trustStore} trustStorePassword: ${server.ssl.trustStorePassword} customMetadata: + apiml: + responseTimeout: 10000 + connectTimeout: 6500 enableUrlEncodedCharacters: true gatewayPort: 10010 gatewayAuthEndpoint: /gateway/api/v1/auth diff --git a/gateway-service/src/main/java/org/zowe/apiml/gateway/config/NettyRoutingFilterApiml.java b/gateway-service/src/main/java/org/zowe/apiml/gateway/config/NettyRoutingFilterApiml.java index 9f10b69e53..c2b40060d7 100644 --- a/gateway-service/src/main/java/org/zowe/apiml/gateway/config/NettyRoutingFilterApiml.java +++ b/gateway-service/src/main/java/org/zowe/apiml/gateway/config/NettyRoutingFilterApiml.java @@ -29,7 +29,6 @@ import java.util.List; import java.util.Optional; -import static org.springframework.cloud.gateway.support.RouteMetadataUtils.CONNECT_TIMEOUT_ATTR; import static org.zowe.apiml.constants.ApimlConstants.HTTP_CLIENT_USE_CLIENT_CERTIFICATE; @Slf4j @@ -66,23 +65,20 @@ static Integer getInteger(Object connectTimeoutAttr) { @Override protected HttpClient getHttpClient(Route route, ServerWebExchange exchange) { // select proper HttpClient instance by attribute apiml.useClientCert - boolean useClientCert = Optional.ofNullable((Boolean) exchange.getAttribute(HTTP_CLIENT_USE_CLIENT_CERTIFICATE)).orElse(Boolean.FALSE); - HttpClient httpClient = useClientCert ? httpClientClientCert : httpClientNoCert; + var useClientCert = Optional.ofNullable((Boolean) exchange.getAttribute(HTTP_CLIENT_USE_CLIENT_CERTIFICATE)).orElse(Boolean.FALSE); + var httpClient = useClientCert ? httpClientClientCert : httpClientNoCert; log.debug("Using client with keystore {}", useClientCert); - Object connectTimeoutAttr = route.getMetadata().get(CONNECT_TIMEOUT_ATTR); - if (connectTimeoutAttr != null) { - // if there is configured timeout, respect it - Integer connectTimeout = getInteger(connectTimeoutAttr); - return httpClient - .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, connectTimeout) - .responseTimeout(Duration.ofMillis(connectTimeout)); - } + var connectTimeoutAttr = route.getMetadata().get("apiml.connectTimeout"); + var responseTimeoutAttr = route.getMetadata().get("apiml.responseTimeout"); + + var responseTimeoutResult = responseTimeoutAttr != null ? Long.parseLong(String.valueOf(responseTimeoutAttr)) : requestTimeout; + var connectTimeoutResult = connectTimeoutAttr != null ? getInteger(connectTimeoutAttr) : requestTimeout; + httpClient = httpClient + .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, connectTimeoutResult) + .responseTimeout(Duration.ofMillis(responseTimeoutResult)); - // otherwise just return selected HttpClient with the default configured timeouts - return httpClient - .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, requestTimeout) - .responseTimeout(Duration.ofMillis(requestTimeout)); + return httpClient; } @Override diff --git a/gateway-service/src/test/java/org/zowe/apiml/gateway/config/NettyRoutingFilterApimlTest.java b/gateway-service/src/test/java/org/zowe/apiml/gateway/config/NettyRoutingFilterApimlTest.java index 7cc215ae9e..dcd50f4602 100644 --- a/gateway-service/src/test/java/org/zowe/apiml/gateway/config/NettyRoutingFilterApimlTest.java +++ b/gateway-service/src/test/java/org/zowe/apiml/gateway/config/NettyRoutingFilterApimlTest.java @@ -28,13 +28,13 @@ import reactor.netty.http.client.HttpClient; import javax.net.ssl.SSLException; +import java.time.Duration; import static io.restassured.RestAssured.given; import static org.apache.http.HttpStatus.SC_OK; import static org.apache.http.HttpStatus.SC_SERVICE_UNAVAILABLE; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; -import static org.springframework.cloud.gateway.support.RouteMetadataUtils.CONNECT_TIMEOUT_ATTR; import static org.zowe.apiml.constants.ApimlConstants.HTTP_CLIENT_USE_CLIENT_CERTIFICATE; class NettyRoutingFilterApimlTest { @@ -92,10 +92,13 @@ class GetHttpClient { NettyRoutingFilterApiml nettyRoutingFilterApiml; private final Route ROUTE_NO_TIMEOUT = Route.async() - .id("1").uri("http://localhost/").predicate(__ -> true) + .id("1").uri("http://localhost/").predicate(__ -> true) .build(); private final Route ROUTE_TIMEOUT = Route.async() - .id("2").uri("http://localhost/").predicate(__ -> true).metadata(CONNECT_TIMEOUT_ATTR, "100") + .id("2").uri("http://localhost/").predicate(__ -> true).metadata("apiml.connectTimeout", "100") + .build(); + private final Route ROUTE_RESPONSE_TIMEOUT = Route.async() + .id("3").uri("http://localhost/").predicate(__ -> true).metadata("apiml.responseTimeout", "23") .build(); MockServerWebExchange serverWebExchange; @@ -143,6 +146,14 @@ void givenTimeoutAndRequirementsForClientCert_whenGetHttpClient_thenCallWithoutC verify(httpClientWithCert).option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 100); } + @Test + void givenTimeoutAndRequirementsForClientCert_whenGetHttpClient_thenCallWithoutClientCertWithCorrectTimeout() { + setUpClient(httpClientWithCert); + serverWebExchange.getAttributes().put(HTTP_CLIENT_USE_CLIENT_CERTIFICATE, Boolean.TRUE); + nettyRoutingFilterApiml.getHttpClient(ROUTE_RESPONSE_TIMEOUT, serverWebExchange); + verify(httpClientWithCert).responseTimeout(Duration.ofMillis(23)); + } + } } diff --git a/integration-tests/src/test/java/org/zowe/apiml/functional/gateway/GatewayRoutingTest.java b/integration-tests/src/test/java/org/zowe/apiml/functional/gateway/GatewayRoutingTest.java index df5a9e87cc..505ae831a2 100644 --- a/integration-tests/src/test/java/org/zowe/apiml/functional/gateway/GatewayRoutingTest.java +++ b/integration-tests/src/test/java/org/zowe/apiml/functional/gateway/GatewayRoutingTest.java @@ -56,7 +56,10 @@ static void setup() { }) void testRoutingWithBasePath(String basePath) throws URISyntaxException { String scgUrl = String.format("%s://%s:%s%s", conf.getScheme(), conf.getHost(), conf.getPort(), basePath); - given().get(new URI(scgUrl)).then().statusCode(200); + given() + .get(new URI(scgUrl)) + .then() + .statusCode(200); } @ParameterizedTest(name = "When header X-Forward-To is set to {0} should return 200") @@ -66,8 +69,11 @@ void testRoutingWithBasePath(String basePath) throws URISyntaxException { }) void testRoutingWithHeader(String forwardTo) throws URISyntaxException { String scgUrl = String.format("%s://%s:%s%s", conf.getScheme(), conf.getHost(), conf.getPort(), DISCOVERABLE_GREET); - given().header(HEADER_X_FORWARD_TO, forwardTo) - .get(new URI(scgUrl)).then().statusCode(200); + given() + .header(HEADER_X_FORWARD_TO, forwardTo) + .get(new URI(scgUrl)) + .then() + .statusCode(200); } @ParameterizedTest(name = "When base path is {0} should return 404") @@ -77,7 +83,10 @@ void testRoutingWithHeader(String forwardTo) throws URISyntaxException { }) void testRoutingWithIncorrectServiceInBasePath(String basePath) throws URISyntaxException { String scgUrl = String.format("%s://%s:%s%s", conf.getScheme(), conf.getHost(), conf.getPort(), basePath); - given().get(new URI(scgUrl)).then().statusCode(404); + given() + .get(new URI(scgUrl)) + .then() + .statusCode(404); } @ParameterizedTest(name = "When header X-Forward-To is set to {0} should return 404") @@ -87,8 +96,11 @@ void testRoutingWithIncorrectServiceInBasePath(String basePath) throws URISyntax }) void testRoutingWithIncorrectServiceInHeader(String forwardTo) throws URISyntaxException { String scgUrl = String.format("%s://%s:%s%s", conf.getScheme(), conf.getHost(), conf.getPort(), NON_EXISTING_SERVICE_ENDPOINT); - given().header(HEADER_X_FORWARD_TO, forwardTo) - .get(new URI(scgUrl)).then().statusCode(404); + given() + .header(HEADER_X_FORWARD_TO, forwardTo) + .get(new URI(scgUrl)) + .then() + .statusCode(404); } @ParameterizedTest(name = "When header X-Forward-To is set to {0} and base path is {1} should return 200 - loopback") @@ -97,8 +109,11 @@ void testRoutingWithIncorrectServiceInHeader(String forwardTo) throws URISyntaxE }) void testWrongRoutingWithHeader(String forwardTo, String endpoint) throws URISyntaxException { String scgUrl = String.format("%s://%s:%s%s", conf.getScheme(), conf.getHost(), conf.getPort(), endpoint); - given().header(HEADER_X_FORWARD_TO, forwardTo) - .get(new URI(scgUrl)).then().statusCode(200); + given() + .header(HEADER_X_FORWARD_TO, forwardTo) + .get(new URI(scgUrl)) + .then() + .statusCode(200); } @ParameterizedTest(name = "When base path is {0} should return 404") @@ -108,13 +123,19 @@ void testWrongRoutingWithHeader(String forwardTo, String endpoint) throws URISyn }) void testWrongRoutingWithBasePath(String basePath) throws URISyntaxException { String scgUrl = String.format("%s://%s:%s%s", conf.getScheme(), conf.getHost(), conf.getPort(), basePath); - given().get(new URI(scgUrl)).then().statusCode(404); + given() + .get(new URI(scgUrl)) + .then() + .statusCode(404); } @Test void givenEndpointDoesNotExistOnRegisteredService() throws URISyntaxException { String scgUrl = String.format("%s://%s:%s%s", conf.getScheme(), conf.getHost(), conf.getPort(), "/dcpassticket/api/v1/unknown"); - given().get(new URI(scgUrl)).then().statusCode(404); + given() + .get(new URI(scgUrl)) + .then() + .statusCode(404); } @ParameterizedTest