Controller:
@RestController
@RequestMapping(value = "/uritest")
public class TestController {
@RequestMapping(method = { RequestMethod.GET })
public ResponseEntity<Void> endpoint(@RequestParam(required = true) String param) {
System.out.println(param);
return new ResponseEntity<>(HttpStatus.OK);
}
}
Integration Test:
@ActiveProfiles("test")
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.DEFINED_PORT)
public class ControllerTest {
@Autowired
private TestRestTemplate testRestTemplate;
@Rule
public WireMockRule wireMockRule = new WireMockRule();
HttpHeaders headers;
@Test
public void testGivenExistingStateRequestWhenCallGetStateThenReturnOkStatusAndProperBody() throws Exception {
final UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromPath("/uritest");
uriBuilder.queryParam("param", "\"\\%");
final HttpEntity<String> entity = new HttpEntity<>(null, headers);
final URI uri = uriBuilder.build().toUri();
testRestTemplate.exchange(uri, HttpMethod.GET, entity, String.class);
testRestTemplate.exchange(uri.toString(), HttpMethod.GET, entity, String.class);
}
}
Output:
"\%
%22%5C%25
There is already a closed issue about this bug: https://github.com/spring-projects/spring-boot/issues/8163
I checked the fix there and it adds a root to the URI if the URI was relative. This issue also happens if the provided string describes a relative URI. I assume the same check should be applied to all of the other methods too where the first parameter is a String instead of an URI.
@Selindek this seems to be happening because the String that gets passed to exchange
is already encoded (which causes the double encoding as @wilkinsona mentioned here Instead of using the uri.toString()
, if "/uritest?param=\"\\%"
is passed, the encoding works fine.
If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.
Closing due to lack of requested feedback. If you would like us to look at this issue, please provide the requested information and we will re-open the issue.
running into this same issue as well...
Spring Boot 1.5.7 .. using RestTemplate and setting a rootURI using RestTemplateBuilder... the rootURI doesnt get applied when the RestTemplate methods are called (eg getForObject ) when using the URI object... have to use the string version of the URI.. This relates to this issue: #7891 but then we run into the double encoding issue.
A workaround is to simply build the uri string manually and use it directly in the RestTemplate call... seems using URI object encodes the URI at some point... before it's used as a string parameter in the RestTemplate method call. Not as ideal, as I do like using URIComponents to build up my request URIs...
Update: Seems using toUriString() of the UriComponents class in the RestTemplate method call works... string is properly encoded.. once!
Just using new URI(enocodedUrl)
in RestTemplateCall
solves the issue...
UriComponentsBuilder
can also be used to prepare encodedUrl
from MultiValueMap
.
Example :
String enocodedUrl = UriComponentsBuilder.fromHttpUrl(URL).queryParams(queryParameterMultiValueMap).build(true).toUriString();
restTemplate.getForEntity(new URI(enocodedUrl ) , String.class);
Same issue in spring-boot 2.0.2 using UriComponentsBuilder with TestRestTemplate.
uriBuilder.toUriString()
encodes space as %2520
(it does: build(false).encode().toUriString()
).uriBuilder.build(false).toUriString()
encodes space as %20
@georgmittendorfer Could you provide a small sample to show the problem?
Small sample (not very sophisticated):
String uriString = UriComponentsBuilder
.fromUriString("http://localhost:1234")
.queryParam("foo", "some value")
.toUriString();
assertTrue(uriString, uriString.contains("foo=some%20value"));
restTemplate.getForEntity(uriString, String.class);
Listening with netcat -s localhost -l -p 1234
will show that %20
is encoded a second time to %2520
:
netcat -s localhost -l -p 1234
GET /?foo=some%2520value HTTP/1.1
Hi @georgmittendorfer,
I think this is the expected behavior in Spring Framework (see SPR-16202 and SPR-14828 for some background on this).
As a general rule, providing a URI String to RestTemplate
means that this String should be expanded (using optional method parameters) and then encoded. If you want to take full control over the encoding, you should then use the method variant taking a URI
as a parameter.
The Spring Framework team recently added some more documentation on the subject of URI encoding. Does that help?
Yes, thank you, that helps. The API is slightly confusing on first contact, though.
Ok thanks!
@georgmittendorfer Thanks馃憤
Most helpful comment
Just using
new URI(enocodedUrl)
inRestTemplateCall
solves the issue...UriComponentsBuilder
can also be used to prepareencodedUrl
fromMultiValueMap
.Example :