Commit 2f50d515 authored by Andy Wilkinson's avatar Andy Wilkinson

Apply root to URIs directly rather than relying on expansion

Previously, TestRestTemplate applied the root URI to URIs by
converting them to a String and then passing the String to the
RestTemplate delegate. Being a String, meant that the URI passed
through RestTemplate's standard URI template expansion processing
using the configured UriTemplateHandler. While this caused the root
URI to be applied, it also had the unwanted side-effect of
encoding the URI for a second time.

This commit updates TestRestTemplate so that, when configured with a
RootUriTemplateHandler, it applies the root URI directly and then
passes a modified URI to the RestTemplate delegate. Being a URI means
that no template expansion is performed and the possible double
encoding is avoided.

Closes gh-8163
parent 7e440292
...@@ -39,6 +39,7 @@ import org.apache.http.protocol.HttpContext; ...@@ -39,6 +39,7 @@ import org.apache.http.protocol.HttpContext;
import org.apache.http.ssl.SSLContextBuilder; import org.apache.http.ssl.SSLContextBuilder;
import org.springframework.boot.web.client.RestTemplateBuilder; import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.boot.web.client.RootUriTemplateHandler;
import org.springframework.core.ParameterizedTypeReference; import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpEntity; import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
...@@ -217,7 +218,7 @@ public class TestRestTemplate { ...@@ -217,7 +218,7 @@ public class TestRestTemplate {
* @see RestTemplate#getForObject(java.net.URI, java.lang.Class) * @see RestTemplate#getForObject(java.net.URI, java.lang.Class)
*/ */
public <T> T getForObject(URI url, Class<T> responseType) throws RestClientException { public <T> T getForObject(URI url, Class<T> responseType) throws RestClientException {
return this.restTemplate.getForObject(url.toString(), responseType); return this.restTemplate.getForObject(applyRootUriIfNecessary(url), responseType);
} }
/** /**
...@@ -269,7 +270,7 @@ public class TestRestTemplate { ...@@ -269,7 +270,7 @@ public class TestRestTemplate {
*/ */
public <T> ResponseEntity<T> getForEntity(URI url, Class<T> responseType) public <T> ResponseEntity<T> getForEntity(URI url, Class<T> responseType)
throws RestClientException { throws RestClientException {
return this.restTemplate.getForEntity(url.toString(), responseType); return this.restTemplate.getForEntity(applyRootUriIfNecessary(url), responseType);
} }
/** /**
...@@ -310,7 +311,7 @@ public class TestRestTemplate { ...@@ -310,7 +311,7 @@ public class TestRestTemplate {
* @see RestTemplate#headForHeaders(java.net.URI) * @see RestTemplate#headForHeaders(java.net.URI)
*/ */
public HttpHeaders headForHeaders(URI url) throws RestClientException { public HttpHeaders headForHeaders(URI url) throws RestClientException {
return this.restTemplate.headForHeaders(url.toString()); return this.restTemplate.headForHeaders(applyRootUriIfNecessary(url));
} }
/** /**
...@@ -374,7 +375,7 @@ public class TestRestTemplate { ...@@ -374,7 +375,7 @@ public class TestRestTemplate {
* @see RestTemplate#postForLocation(java.net.URI, java.lang.Object) * @see RestTemplate#postForLocation(java.net.URI, java.lang.Object)
*/ */
public URI postForLocation(URI url, Object request) throws RestClientException { public URI postForLocation(URI url, Object request) throws RestClientException {
return this.restTemplate.postForLocation(url.toString(), request); return this.restTemplate.postForLocation(applyRootUriIfNecessary(url), request);
} }
/** /**
...@@ -442,7 +443,8 @@ public class TestRestTemplate { ...@@ -442,7 +443,8 @@ public class TestRestTemplate {
*/ */
public <T> T postForObject(URI url, Object request, Class<T> responseType) public <T> T postForObject(URI url, Object request, Class<T> responseType)
throws RestClientException { throws RestClientException {
return this.restTemplate.postForObject(url.toString(), request, responseType); return this.restTemplate.postForObject(applyRootUriIfNecessary(url), request,
responseType);
} }
/** /**
...@@ -511,7 +513,8 @@ public class TestRestTemplate { ...@@ -511,7 +513,8 @@ public class TestRestTemplate {
*/ */
public <T> ResponseEntity<T> postForEntity(URI url, Object request, public <T> ResponseEntity<T> postForEntity(URI url, Object request,
Class<T> responseType) throws RestClientException { Class<T> responseType) throws RestClientException {
return this.restTemplate.postForEntity(url.toString(), request, responseType); return this.restTemplate.postForEntity(applyRootUriIfNecessary(url), request,
responseType);
} }
/** /**
...@@ -564,7 +567,7 @@ public class TestRestTemplate { ...@@ -564,7 +567,7 @@ public class TestRestTemplate {
* @see RestTemplate#put(java.net.URI, java.lang.Object) * @see RestTemplate#put(java.net.URI, java.lang.Object)
*/ */
public void put(URI url, Object request) throws RestClientException { public void put(URI url, Object request) throws RestClientException {
this.restTemplate.put(url.toString(), request); this.restTemplate.put(applyRootUriIfNecessary(url), request);
} }
/** /**
...@@ -630,7 +633,8 @@ public class TestRestTemplate { ...@@ -630,7 +633,8 @@ public class TestRestTemplate {
*/ */
public <T> T patchForObject(URI url, Object request, Class<T> responseType) public <T> T patchForObject(URI url, Object request, Class<T> responseType)
throws RestClientException { throws RestClientException {
return this.restTemplate.patchForObject(url.toString(), request, responseType); return this.restTemplate.patchForObject(applyRootUriIfNecessary(url), request,
responseType);
} }
...@@ -668,7 +672,7 @@ public class TestRestTemplate { ...@@ -668,7 +672,7 @@ public class TestRestTemplate {
* @see RestTemplate#delete(java.net.URI) * @see RestTemplate#delete(java.net.URI)
*/ */
public void delete(URI url) throws RestClientException { public void delete(URI url) throws RestClientException {
this.restTemplate.delete(url.toString()); this.restTemplate.delete(applyRootUriIfNecessary(url));
} }
/** /**
...@@ -709,7 +713,7 @@ public class TestRestTemplate { ...@@ -709,7 +713,7 @@ public class TestRestTemplate {
* @see RestTemplate#optionsForAllow(java.net.URI) * @see RestTemplate#optionsForAllow(java.net.URI)
*/ */
public Set<HttpMethod> optionsForAllow(URI url) throws RestClientException { public Set<HttpMethod> optionsForAllow(URI url) throws RestClientException {
return this.restTemplate.optionsForAllow(url.toString()); return this.restTemplate.optionsForAllow(applyRootUriIfNecessary(url));
} }
/** /**
...@@ -777,8 +781,8 @@ public class TestRestTemplate { ...@@ -777,8 +781,8 @@ public class TestRestTemplate {
public <T> ResponseEntity<T> exchange(URI url, HttpMethod method, public <T> ResponseEntity<T> exchange(URI url, HttpMethod method,
HttpEntity<?> requestEntity, Class<T> responseType) HttpEntity<?> requestEntity, Class<T> responseType)
throws RestClientException { throws RestClientException {
return this.restTemplate.exchange(url.toString(), method, requestEntity, return this.restTemplate.exchange(applyRootUriIfNecessary(url), method,
responseType); requestEntity, responseType);
} }
/** /**
...@@ -860,8 +864,8 @@ public class TestRestTemplate { ...@@ -860,8 +864,8 @@ public class TestRestTemplate {
public <T> ResponseEntity<T> exchange(URI url, HttpMethod method, public <T> ResponseEntity<T> exchange(URI url, HttpMethod method,
HttpEntity<?> requestEntity, ParameterizedTypeReference<T> responseType) HttpEntity<?> requestEntity, ParameterizedTypeReference<T> responseType)
throws RestClientException { throws RestClientException {
return this.restTemplate.exchange(url.toString(), method, requestEntity, return this.restTemplate.exchange(applyRootUriIfNecessary(url), method,
responseType); requestEntity, responseType);
} }
/** /**
...@@ -882,7 +886,7 @@ public class TestRestTemplate { ...@@ -882,7 +886,7 @@ public class TestRestTemplate {
public <T> ResponseEntity<T> exchange(RequestEntity<?> requestEntity, public <T> ResponseEntity<T> exchange(RequestEntity<?> requestEntity,
Class<T> responseType) throws RestClientException { Class<T> responseType) throws RestClientException {
return this.restTemplate.exchange( return this.restTemplate.exchange(
createRequestEntityWithExpandedUri(requestEntity), responseType); createRequestEntityWithRootAppliedUri(requestEntity), responseType);
} }
/** /**
...@@ -905,7 +909,7 @@ public class TestRestTemplate { ...@@ -905,7 +909,7 @@ public class TestRestTemplate {
public <T> ResponseEntity<T> exchange(RequestEntity<?> requestEntity, public <T> ResponseEntity<T> exchange(RequestEntity<?> requestEntity,
ParameterizedTypeReference<T> responseType) throws RestClientException { ParameterizedTypeReference<T> responseType) throws RestClientException {
return this.restTemplate.exchange( return this.restTemplate.exchange(
createRequestEntityWithExpandedUri(requestEntity), responseType); createRequestEntityWithRootAppliedUri(requestEntity), responseType);
} }
/** /**
...@@ -972,8 +976,8 @@ public class TestRestTemplate { ...@@ -972,8 +976,8 @@ public class TestRestTemplate {
*/ */
public <T> T execute(URI url, HttpMethod method, RequestCallback requestCallback, public <T> T execute(URI url, HttpMethod method, RequestCallback requestCallback,
ResponseExtractor<T> responseExtractor) throws RestClientException { ResponseExtractor<T> responseExtractor) throws RestClientException {
return this.restTemplate.execute(url.toString(), method, requestCallback, return this.restTemplate.execute(applyRootUriIfNecessary(url), method,
responseExtractor); requestCallback, responseExtractor);
} }
/** /**
...@@ -1008,12 +1012,21 @@ public class TestRestTemplate { ...@@ -1008,12 +1012,21 @@ public class TestRestTemplate {
} }
@SuppressWarnings({ "rawtypes", "unchecked" }) @SuppressWarnings({ "rawtypes", "unchecked" })
private RequestEntity<?> createRequestEntityWithExpandedUri( private RequestEntity<?> createRequestEntityWithRootAppliedUri(
RequestEntity<?> requestEntity) { RequestEntity<?> requestEntity) {
URI expandedUri = this.restTemplate.getUriTemplateHandler()
.expand(requestEntity.getUrl().toString());
return new RequestEntity(requestEntity.getBody(), requestEntity.getHeaders(), return new RequestEntity(requestEntity.getBody(), requestEntity.getHeaders(),
requestEntity.getMethod(), expandedUri, requestEntity.getType()); requestEntity.getMethod(),
applyRootUriIfNecessary(requestEntity.getUrl()), requestEntity.getType());
}
private URI applyRootUriIfNecessary(URI uri) {
UriTemplateHandler uriTemplateHandler = this.restTemplate.getUriTemplateHandler();
if ((uriTemplateHandler instanceof RootUriTemplateHandler)
&& uri.toString().startsWith("/")) {
return URI.create(((RootUriTemplateHandler) uriTemplateHandler).getRootUri()
+ uri.toString());
}
return uri;
} }
/** /**
......
...@@ -38,6 +38,7 @@ import org.springframework.http.client.ClientHttpRequestInterceptor; ...@@ -38,6 +38,7 @@ import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.client.InterceptingClientHttpRequestFactory; import org.springframework.http.client.InterceptingClientHttpRequestFactory;
import org.springframework.http.client.support.BasicAuthorizationInterceptor; import org.springframework.http.client.support.BasicAuthorizationInterceptor;
import org.springframework.mock.env.MockEnvironment;
import org.springframework.mock.http.client.MockClientHttpRequest; import org.springframework.mock.http.client.MockClientHttpRequest;
import org.springframework.mock.http.client.MockClientHttpResponse; import org.springframework.mock.http.client.MockClientHttpResponse;
import org.springframework.test.util.ReflectionTestUtils; import org.springframework.test.util.ReflectionTestUtils;
...@@ -47,7 +48,6 @@ import org.springframework.web.client.ResponseErrorHandler; ...@@ -47,7 +48,6 @@ import org.springframework.web.client.ResponseErrorHandler;
import org.springframework.web.client.RestOperations; import org.springframework.web.client.RestOperations;
import org.springframework.web.client.RestTemplate; import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.DefaultUriTemplateHandler; import org.springframework.web.util.DefaultUriTemplateHandler;
import org.springframework.web.util.UriTemplateHandler;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given; import static org.mockito.BDDMockito.given;
...@@ -427,18 +427,18 @@ public class TestRestTemplateTests { ...@@ -427,18 +427,18 @@ public class TestRestTemplateTests {
ClientHttpRequestFactory requestFactory = mock(ClientHttpRequestFactory.class); ClientHttpRequestFactory requestFactory = mock(ClientHttpRequestFactory.class);
MockClientHttpRequest request = new MockClientHttpRequest(); MockClientHttpRequest request = new MockClientHttpRequest();
request.setResponse(new MockClientHttpResponse(new byte[0], HttpStatus.OK)); request.setResponse(new MockClientHttpResponse(new byte[0], HttpStatus.OK));
URI relativeUri = URI.create("a/b/c.txt"); URI absoluteUri = URI
URI absoluteUri = URI.create("http://localhost:8080/" + relativeUri.toString()); .create("http://localhost:8080/a/b/c.txt?param=%7Bsomething%7D");
given(requestFactory.createRequest(eq(absoluteUri), (HttpMethod) any())) given(requestFactory.createRequest(eq(absoluteUri), (HttpMethod) any()))
.willReturn(request); .willReturn(request);
RestTemplate delegate = new RestTemplate(); RestTemplate delegate = new RestTemplate();
TestRestTemplate template = new TestRestTemplate(delegate); TestRestTemplate template = new TestRestTemplate(delegate);
delegate.setRequestFactory(requestFactory); delegate.setRequestFactory(requestFactory);
UriTemplateHandler uriTemplateHandler = mock(UriTemplateHandler.class); LocalHostUriTemplateHandler uriTemplateHandler = new LocalHostUriTemplateHandler(
given(uriTemplateHandler.expand(relativeUri.toString(), new Object[0])) new MockEnvironment());
.willReturn(absoluteUri);
template.setUriTemplateHandler(uriTemplateHandler); template.setUriTemplateHandler(uriTemplateHandler);
callback.doWithTestRestTemplate(template, relativeUri); callback.doWithTestRestTemplate(template,
URI.create("/a/b/c.txt?param=%7Bsomething%7D"));
verify(requestFactory).createRequest(eq(absoluteUri), (HttpMethod) any()); verify(requestFactory).createRequest(eq(absoluteUri), (HttpMethod) any());
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment