Prevent double encoding in setPath method

The setPath method was causing URLs to be encoded twice under certain conditions.
This fix ensures proper handling of parameters to avoid redundant encoding.

Signed-off-by: raccoonback <kosb15@naver.com>
This commit is contained in:
raccoonback
2025-01-05 15:54:56 +09:00
parent 1f10961bd7
commit 07aca3e63e
2 changed files with 164 additions and 2 deletions

View File

@@ -350,9 +350,11 @@ public abstract class BeforeFilterFunctions {
return request -> {
Map<String, Object> uriVariables = MvcUtils.getUriTemplateVariables(request);
URI uri = uriTemplate.expand(uriVariables);
String newPath = uri.getRawPath();
URI prefixedUri = UriComponentsBuilder.fromUri(request.uri()).replacePath(newPath).build().toUri();
URI prefixedUri = UriComponentsBuilder.fromUri(request.uri())
.replacePath(uri.getRawPath())
.build(true)
.toUri();
return ServerRequest.from(request).uri(prefixedUri).build();
};
}

View File

@@ -0,0 +1,160 @@
/*
* Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.gateway.server.mvc.filter;
import java.util.Collections;
import org.junit.jupiter.api.Test;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.web.servlet.function.ServerRequest;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author raccoonback
*/
class BeforeFilterFunctionsTests {
@Test
void rewriteRequestParameter() {
MockHttpServletRequest servletRequest = MockMvcRequestBuilders.get("http://localhost/path")
.param("foo", "bar")
.param("baz", "qux")
.buildRequest(null);
ServerRequest request = ServerRequest.create(servletRequest, Collections.emptyList());
ServerRequest result = BeforeFilterFunctions.rewriteRequestParameter("foo", "replacement").apply(request);
assertThat(result.param("foo")).isPresent().hasValue("replacement");
assertThat(result.uri().toString()).hasToString("http://localhost/path?baz=qux&foo=replacement");
}
@Test
void rewriteOnlyFirstRequestParameter() {
MockHttpServletRequest servletRequest = MockMvcRequestBuilders.get("http://localhost/path")
.param("foo", "bar_1")
.param("foo", "bar_2")
.param("foo", "bar_3")
.param("baz", "qux")
.buildRequest(null);
ServerRequest request = ServerRequest.create(servletRequest, Collections.emptyList());
ServerRequest result = BeforeFilterFunctions.rewriteRequestParameter("foo", "replacement").apply(request);
assertThat(result.param("foo")).isPresent().hasValue("replacement");
assertThat(result.uri().toString()).hasToString("http://localhost/path?baz=qux&foo=replacement");
}
@Test
void rewriteEncodedRequestParameter() {
MockHttpServletRequest servletRequest = MockMvcRequestBuilders.get("http://localhost/path")
.param("foo[]", "bar")
.param("baz", "qux")
.buildRequest(null);
ServerRequest request = ServerRequest.create(servletRequest, Collections.emptyList());
ServerRequest result = BeforeFilterFunctions.rewriteRequestParameter("foo[]", "replacement[]").apply(request);
assertThat(result.param("foo[]")).isPresent().hasValue("replacement[]");
assertThat(result.uri().toString()).hasToString("http://localhost/path?baz=qux&foo%5B%5D=replacement%5B%5D");
}
@Test
void rewriteRequestParameterWithEncodedRemainParameters() {
MockHttpServletRequest servletRequest = MockMvcRequestBuilders.get("http://localhost/path")
.param("foo", "bar")
.param("baz[]", "qux[]")
.buildRequest(null);
ServerRequest request = ServerRequest.create(servletRequest, Collections.emptyList());
ServerRequest result = BeforeFilterFunctions.rewriteRequestParameter("foo", "replacement").apply(request);
assertThat(result.param("foo")).isPresent().hasValue("replacement");
assertThat(result.uri().toString()).hasToString("http://localhost/path?baz%5B%5D=qux%5B%5D&foo=replacement");
}
@Test
void rewriteRequestParameterWithEncodedPath() {
MockHttpServletRequest servletRequest = MockMvcRequestBuilders.get("http://localhost/path/é/last")
.param("foo", "bar")
.buildRequest(null);
ServerRequest request = ServerRequest.create(servletRequest, Collections.emptyList());
ServerRequest result = BeforeFilterFunctions.rewriteRequestParameter("foo", "replacement").apply(request);
assertThat(result.param("foo")).isPresent().hasValue("replacement");
assertThat(result.uri().toString()).hasToString("http://localhost/path/%C3%A9/last?foo=replacement");
}
@Test
void setPath() {
MockHttpServletRequest servletRequest = MockMvcRequestBuilders.get("http://localhost/legacy/path")
.buildRequest(null);
ServerRequest request = ServerRequest.create(servletRequest, Collections.emptyList());
ServerRequest result = BeforeFilterFunctions.setPath("/new/path").apply(request);
assertThat(result.uri().toString()).isEqualTo("http://localhost/new/path");
}
@Test
void setEncodedPath() {
MockHttpServletRequest servletRequest = MockMvcRequestBuilders.get("http://localhost/legacy/path")
.buildRequest(null);
ServerRequest request = ServerRequest.create(servletRequest, Collections.emptyList());
ServerRequest result = BeforeFilterFunctions.setPath("/new/é").apply(request);
assertThat(result.uri().toString()).isEqualTo("http://localhost/new/%C3%A9");
}
@Test
void setPathWithParameters() {
MockHttpServletRequest servletRequest = MockMvcRequestBuilders.get("http://localhost/legacy/path")
.queryParam("foo", "bar")
.buildRequest(null);
ServerRequest request = ServerRequest.create(servletRequest, Collections.emptyList());
ServerRequest result = BeforeFilterFunctions.setPath("/new/path").apply(request);
assertThat(result.uri().toString()).isEqualTo("http://localhost/new/path?foo=bar");
}
@Test
void setPathWithEncodedParameters() {
MockHttpServletRequest servletRequest = MockMvcRequestBuilders.get("http://localhost/legacy/path")
.queryParam("foo[]", "bar[]")
.buildRequest(null);
ServerRequest request = ServerRequest.create(servletRequest, Collections.emptyList());
ServerRequest result = BeforeFilterFunctions.setPath("/new/path").apply(request);
assertThat(result.uri().toString()).isEqualTo("http://localhost/new/path?foo%5B%5D=bar%5B%5D");
}
}