From 044e179304b047233911d405f30a19a48cfafed9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=A1clav=20Plic?= Date: Thu, 29 Sep 2022 21:34:53 +0200 Subject: [PATCH] RestTemplateEurekaHttpClient - Encode special characters; fixes gh-4121 --- .../http/RestTemplateEurekaHttpClient.java | 65 +++++++++++-------- 1 file changed, 39 insertions(+), 26 deletions(-) diff --git a/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/http/RestTemplateEurekaHttpClient.java b/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/http/RestTemplateEurekaHttpClient.java index efc4df4e5e..c3a54d16ce 100644 --- a/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/http/RestTemplateEurekaHttpClient.java +++ b/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/http/RestTemplateEurekaHttpClient.java @@ -16,6 +16,7 @@ package org.springframework.cloud.netflix.eureka.http; +import java.net.URI; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -40,6 +41,7 @@ import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.client.RestTemplate; +import org.springframework.web.util.UriComponentsBuilder; import static com.netflix.discovery.shared.transport.EurekaHttpResponse.anEurekaHttpResponse; @@ -68,13 +70,14 @@ public String getServiceUrl() { @Override public EurekaHttpResponse register(InstanceInfo info) { - String urlPath = serviceUrl + "apps/" + info.getAppName(); + URI uri = UriComponentsBuilder.fromHttpUrl(serviceUrl).path("apps/{appName}").buildAndExpand(info.getAppName()) + .toUri(); HttpHeaders headers = new HttpHeaders(); headers.add(HttpHeaders.ACCEPT_ENCODING, "gzip"); headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE); - ResponseEntity response = restTemplate.exchange(urlPath, HttpMethod.POST, new HttpEntity<>(info, headers), + ResponseEntity response = restTemplate.exchange(uri, HttpMethod.POST, new HttpEntity<>(info, headers), Void.class); return anEurekaHttpResponse(response.getStatusCode().value()).headers(headersOf(response)).build(); @@ -82,9 +85,10 @@ public EurekaHttpResponse register(InstanceInfo info) { @Override public EurekaHttpResponse cancel(String appName, String id) { - String urlPath = serviceUrl + "apps/" + appName + '/' + id; + URI uri = UriComponentsBuilder.fromHttpUrl(serviceUrl).path("apps/{appName}/{id}").buildAndExpand(appName, id) + .toUri(); - ResponseEntity response = restTemplate.exchange(urlPath, HttpMethod.DELETE, null, Void.class); + ResponseEntity response = restTemplate.exchange(uri, HttpMethod.DELETE, null, Void.class); return anEurekaHttpResponse(response.getStatusCode().value()).headers(headersOf(response)).build(); } @@ -92,12 +96,17 @@ public EurekaHttpResponse cancel(String appName, String id) { @Override public EurekaHttpResponse sendHeartBeat(String appName, String id, InstanceInfo info, InstanceStatus overriddenStatus) { - String urlPath = serviceUrl + "apps/" + appName + '/' + id + "?status=" + info.getStatus().toString() - + "&lastDirtyTimestamp=" + info.getLastDirtyTimestamp().toString() - + (overriddenStatus != null ? "&overriddenstatus=" + overriddenStatus.name() : ""); + UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromHttpUrl(serviceUrl).path("apps/{appName}/{id}") + .queryParam("status", info.getStatus().toString()) + .queryParam("lastDirtyTimestamp", info.getLastDirtyTimestamp().toString()); - ResponseEntity response = restTemplate.exchange(urlPath, HttpMethod.PUT, null, - InstanceInfo.class); + if (overriddenStatus != null) { + uriBuilder = uriBuilder.queryParam("overriddenstatus", overriddenStatus.name()); + } + + URI uri = uriBuilder.buildAndExpand(appName, id).toUri(); + + ResponseEntity response = restTemplate.exchange(uri, HttpMethod.PUT, null, InstanceInfo.class); EurekaHttpResponseBuilder eurekaResponseBuilder = anEurekaHttpResponse( response.getStatusCode().value(), InstanceInfo.class).headers(headersOf(response)); @@ -112,20 +121,23 @@ public EurekaHttpResponse sendHeartBeat(String appName, String id, @Override public EurekaHttpResponse statusUpdate(String appName, String id, InstanceStatus newStatus, InstanceInfo info) { - String urlPath = serviceUrl + "apps/" + appName + '/' + id + "/status?value=" + newStatus.name() - + "&lastDirtyTimestamp=" + info.getLastDirtyTimestamp().toString(); + URI uri = UriComponentsBuilder.fromHttpUrl(serviceUrl).path("apps/{appName}/{id}/status") + .queryParam("value", newStatus.name()) + .queryParam("lastDirtyTimestamp", info.getLastDirtyTimestamp().toString()).buildAndExpand(appName, id) + .toUri(); - ResponseEntity response = restTemplate.exchange(urlPath, HttpMethod.PUT, null, Void.class); + ResponseEntity response = restTemplate.exchange(uri, HttpMethod.PUT, null, Void.class); return anEurekaHttpResponse(response.getStatusCode().value()).headers(headersOf(response)).build(); } @Override public EurekaHttpResponse deleteStatusOverride(String appName, String id, InstanceInfo info) { - String urlPath = serviceUrl + "apps/" + appName + '/' + id + "/status?lastDirtyTimestamp=" - + info.getLastDirtyTimestamp().toString(); + URI uri = UriComponentsBuilder.fromHttpUrl(serviceUrl).path("apps/{appName}/{id}/status") + .queryParam("lastDirtyTimestamp", info.getLastDirtyTimestamp().toString()).buildAndExpand(appName, id) + .toUri(); - ResponseEntity response = restTemplate.exchange(urlPath, HttpMethod.DELETE, null, Void.class); + ResponseEntity response = restTemplate.exchange(uri, HttpMethod.DELETE, null, Void.class); return anEurekaHttpResponse(response.getStatusCode().value()).headers(headersOf(response)).build(); } @@ -136,13 +148,15 @@ public EurekaHttpResponse getApplications(String... regions) { } private EurekaHttpResponse getApplicationsInternal(String urlPath, String[] regions) { - String url = serviceUrl + urlPath; + UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromHttpUrl(serviceUrl).path(urlPath); if (regions != null && regions.length > 0) { - url = url + (urlPath.contains("?") ? "&" : "?") + "regions=" + StringUtil.join(regions); + uriBuilder = uriBuilder.queryParam("regions", StringUtil.join(regions)); } - ResponseEntity response = restTemplate.exchange(url, HttpMethod.GET, null, + URI uri = uriBuilder.build().toUri(); + + ResponseEntity response = restTemplate.exchange(uri, HttpMethod.GET, null, EurekaApplications.class); return anEurekaHttpResponse(response.getStatusCode().value(), @@ -167,9 +181,9 @@ public EurekaHttpResponse getSecureVip(String secureVipAddress, St @Override public EurekaHttpResponse getApplication(String appName) { - String urlPath = serviceUrl + "apps/" + appName; + URI uri = UriComponentsBuilder.fromHttpUrl(serviceUrl).path("apps/{appName}").buildAndExpand(appName).toUri(); - ResponseEntity response = restTemplate.exchange(urlPath, HttpMethod.GET, null, Application.class); + ResponseEntity response = restTemplate.exchange(uri, HttpMethod.GET, null, Application.class); Application application = response.getStatusCode().value() == HttpStatus.OK.value() && response.hasBody() ? response.getBody() : null; @@ -179,19 +193,18 @@ public EurekaHttpResponse getApplication(String appName) { @Override public EurekaHttpResponse getInstance(String appName, String id) { - return getInstanceInternal("apps/" + appName + '/' + id); + return getInstanceInternal("apps", appName, id); } @Override public EurekaHttpResponse getInstance(String id) { - return getInstanceInternal("instances/" + id); + return getInstanceInternal("instances", id); } - private EurekaHttpResponse getInstanceInternal(String urlPath) { - urlPath = serviceUrl + urlPath; + private EurekaHttpResponse getInstanceInternal(String... pathSegments) { + URI uri = UriComponentsBuilder.fromHttpUrl(serviceUrl).pathSegment(pathSegments).build().toUri(); - ResponseEntity response = restTemplate.exchange(urlPath, HttpMethod.GET, null, - InstanceInfo.class); + ResponseEntity response = restTemplate.exchange(uri, HttpMethod.GET, null, InstanceInfo.class); return anEurekaHttpResponse(response.getStatusCode().value(), response.getStatusCode().value() == HttpStatus.OK.value() && response.hasBody() ? response.getBody()