spring-cloud-gateway icon indicating copy to clipboard operation
spring-cloud-gateway copied to clipboard

Some character are not encoded in UriComponentsBuilder

Open Nhoutain opened this issue 10 months ago • 0 comments

I'm currently experimenting some weird behaviour when migrate from Zuul (with spring 5) to spring gateway mvc (with spring 6). During this migration, I see that the parameter are not alway correctly encoded to the downstream services.

Issue are linked to issue1 and issue2.

I reduce the scope of the issue, and observe that some parameters are not encoded in the parameter, and I really don't understand why it's the current behaviour.

Char Encoded in URI Encoded in PARAM
@ 🔴 🔴
[ 🟢 🔴
% 🟢 🟢
'& 🟢 🔴
'+ 🔴 🔴
'{ 🟢 🟢
'? 🟢 🔴

Can someone explain me why this is a wanted behaviour, if not a bug?

        String uri = UriComponentsBuilder.fromPath("/user@[%&+{?")
                .scheme("http")
                .host("localhost")
                .port("9099")
                .replaceQueryParams(new LinkedMultiValueMap<>(
                        Map.of(
                                "at", List.of("@"),
                                "squareBracket", List.of("["),
                                "percent", List.of("%"),
                                "and", List.of("&"),
                                "plus", List.of("+"),
                                "bracket", List.of("{"),
                                "point", List.of("?")
                        )
                ))
                .build(false)
                .toUri()
                .toString();

// uri = http://localhost:9099/user@%5B%25&+%7B%3F?at=@&and=&&squareBracket=[&point=?&percent=%25&bracket=%7B&plus=+

Note: I voluntary keep the code close to org.springframework.cloud.gateway.server.mvc.handler.ProxyExchangeHandlerFunction#handle in spring gateway 4.1.6:

	@Override
	public ServerResponse handle(ServerRequest serverRequest) {
		URI uri = uriResolver.apply(serverRequest);
		boolean encoded = containsEncodedQuery(serverRequest.uri(), serverRequest.params());
		// @formatter:off
		URI url = UriComponentsBuilder.fromUri(serverRequest.uri())
				.scheme(uri.getScheme())
				.host(uri.getHost())
				.port(uri.getPort())
				.replaceQueryParams(serverRequest.params())
				.build(encoded)
				.toUri();
		// @formatter:on

		HttpHeaders filteredRequestHeaders = filterHeaders(this.requestHttpHeadersFilters,
				serverRequest.headers().asHttpHeaders(), serverRequest);

		boolean preserveHost = (boolean) serverRequest.attributes()
			.getOrDefault(MvcUtils.PRESERVE_HOST_HEADER_ATTRIBUTE, false);
		if (preserveHost) {
			filteredRequestHeaders.set(HttpHeaders.HOST, serverRequest.headers().firstHeader(HttpHeaders.HOST));
		}
		else {
			filteredRequestHeaders.remove(HttpHeaders.HOST);
		}

		// @formatter:off
		ProxyExchange.Request proxyRequest = proxyExchange.request(serverRequest).uri(url)
				.headers(filteredRequestHeaders)
				// TODO: allow injection of ResponseConsumer
				.responseConsumer((response, serverResponse) -> {
					HttpHeaders httpHeaders = filterHeaders(this.responseHttpHeadersFilters, response.getHeaders(), serverResponse);
					serverResponse.headers().putAll(httpHeaders);
				})
				.build();
		// @formatter:on
		return proxyExchange.exchange(proxyRequest);
	}
```

Nhoutain avatar Mar 21 '25 09:03 Nhoutain