Skip to content

Commit 07aca3e

Browse files
committed
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>
1 parent 1f10961 commit 07aca3e

File tree

2 files changed

+164
-2
lines changed

2 files changed

+164
-2
lines changed

spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctions.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -350,9 +350,11 @@ public static Function<ServerRequest, ServerRequest> setPath(String path) {
350350
return request -> {
351351
Map<String, Object> uriVariables = MvcUtils.getUriTemplateVariables(request);
352352
URI uri = uriTemplate.expand(uriVariables);
353-
String newPath = uri.getRawPath();
354353

355-
URI prefixedUri = UriComponentsBuilder.fromUri(request.uri()).replacePath(newPath).build().toUri();
354+
URI prefixedUri = UriComponentsBuilder.fromUri(request.uri())
355+
.replacePath(uri.getRawPath())
356+
.build(true)
357+
.toUri();
356358
return ServerRequest.from(request).uri(prefixedUri).build();
357359
};
358360
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
/*
2+
* Copyright 2013-2025 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.cloud.gateway.server.mvc.filter;
18+
19+
import java.util.Collections;
20+
21+
import org.junit.jupiter.api.Test;
22+
23+
import org.springframework.mock.web.MockHttpServletRequest;
24+
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
25+
import org.springframework.web.servlet.function.ServerRequest;
26+
27+
import static org.assertj.core.api.Assertions.assertThat;
28+
29+
/**
30+
* @author raccoonback
31+
*/
32+
class BeforeFilterFunctionsTests {
33+
34+
@Test
35+
void rewriteRequestParameter() {
36+
MockHttpServletRequest servletRequest = MockMvcRequestBuilders.get("http://localhost/path")
37+
.param("foo", "bar")
38+
.param("baz", "qux")
39+
.buildRequest(null);
40+
41+
ServerRequest request = ServerRequest.create(servletRequest, Collections.emptyList());
42+
43+
ServerRequest result = BeforeFilterFunctions.rewriteRequestParameter("foo", "replacement").apply(request);
44+
45+
assertThat(result.param("foo")).isPresent().hasValue("replacement");
46+
assertThat(result.uri().toString()).hasToString("http://localhost/path?baz=qux&foo=replacement");
47+
}
48+
49+
@Test
50+
void rewriteOnlyFirstRequestParameter() {
51+
MockHttpServletRequest servletRequest = MockMvcRequestBuilders.get("http://localhost/path")
52+
.param("foo", "bar_1")
53+
.param("foo", "bar_2")
54+
.param("foo", "bar_3")
55+
.param("baz", "qux")
56+
.buildRequest(null);
57+
58+
ServerRequest request = ServerRequest.create(servletRequest, Collections.emptyList());
59+
60+
ServerRequest result = BeforeFilterFunctions.rewriteRequestParameter("foo", "replacement").apply(request);
61+
62+
assertThat(result.param("foo")).isPresent().hasValue("replacement");
63+
assertThat(result.uri().toString()).hasToString("http://localhost/path?baz=qux&foo=replacement");
64+
}
65+
66+
@Test
67+
void rewriteEncodedRequestParameter() {
68+
MockHttpServletRequest servletRequest = MockMvcRequestBuilders.get("http://localhost/path")
69+
.param("foo[]", "bar")
70+
.param("baz", "qux")
71+
.buildRequest(null);
72+
73+
ServerRequest request = ServerRequest.create(servletRequest, Collections.emptyList());
74+
75+
ServerRequest result = BeforeFilterFunctions.rewriteRequestParameter("foo[]", "replacement[]").apply(request);
76+
77+
assertThat(result.param("foo[]")).isPresent().hasValue("replacement[]");
78+
assertThat(result.uri().toString()).hasToString("http://localhost/path?baz=qux&foo%5B%5D=replacement%5B%5D");
79+
}
80+
81+
@Test
82+
void rewriteRequestParameterWithEncodedRemainParameters() {
83+
MockHttpServletRequest servletRequest = MockMvcRequestBuilders.get("http://localhost/path")
84+
.param("foo", "bar")
85+
.param("baz[]", "qux[]")
86+
.buildRequest(null);
87+
88+
ServerRequest request = ServerRequest.create(servletRequest, Collections.emptyList());
89+
90+
ServerRequest result = BeforeFilterFunctions.rewriteRequestParameter("foo", "replacement").apply(request);
91+
92+
assertThat(result.param("foo")).isPresent().hasValue("replacement");
93+
assertThat(result.uri().toString()).hasToString("http://localhost/path?baz%5B%5D=qux%5B%5D&foo=replacement");
94+
}
95+
96+
@Test
97+
void rewriteRequestParameterWithEncodedPath() {
98+
MockHttpServletRequest servletRequest = MockMvcRequestBuilders.get("http://localhost/path/é/last")
99+
.param("foo", "bar")
100+
.buildRequest(null);
101+
102+
ServerRequest request = ServerRequest.create(servletRequest, Collections.emptyList());
103+
104+
ServerRequest result = BeforeFilterFunctions.rewriteRequestParameter("foo", "replacement").apply(request);
105+
106+
assertThat(result.param("foo")).isPresent().hasValue("replacement");
107+
assertThat(result.uri().toString()).hasToString("http://localhost/path/%C3%A9/last?foo=replacement");
108+
}
109+
110+
@Test
111+
void setPath() {
112+
MockHttpServletRequest servletRequest = MockMvcRequestBuilders.get("http://localhost/legacy/path")
113+
.buildRequest(null);
114+
115+
ServerRequest request = ServerRequest.create(servletRequest, Collections.emptyList());
116+
117+
ServerRequest result = BeforeFilterFunctions.setPath("/new/path").apply(request);
118+
119+
assertThat(result.uri().toString()).isEqualTo("http://localhost/new/path");
120+
}
121+
122+
@Test
123+
void setEncodedPath() {
124+
MockHttpServletRequest servletRequest = MockMvcRequestBuilders.get("http://localhost/legacy/path")
125+
.buildRequest(null);
126+
127+
ServerRequest request = ServerRequest.create(servletRequest, Collections.emptyList());
128+
129+
ServerRequest result = BeforeFilterFunctions.setPath("/new/é").apply(request);
130+
131+
assertThat(result.uri().toString()).isEqualTo("http://localhost/new/%C3%A9");
132+
}
133+
134+
@Test
135+
void setPathWithParameters() {
136+
MockHttpServletRequest servletRequest = MockMvcRequestBuilders.get("http://localhost/legacy/path")
137+
.queryParam("foo", "bar")
138+
.buildRequest(null);
139+
140+
ServerRequest request = ServerRequest.create(servletRequest, Collections.emptyList());
141+
142+
ServerRequest result = BeforeFilterFunctions.setPath("/new/path").apply(request);
143+
144+
assertThat(result.uri().toString()).isEqualTo("http://localhost/new/path?foo=bar");
145+
}
146+
147+
@Test
148+
void setPathWithEncodedParameters() {
149+
MockHttpServletRequest servletRequest = MockMvcRequestBuilders.get("http://localhost/legacy/path")
150+
.queryParam("foo[]", "bar[]")
151+
.buildRequest(null);
152+
153+
ServerRequest request = ServerRequest.create(servletRequest, Collections.emptyList());
154+
155+
ServerRequest result = BeforeFilterFunctions.setPath("/new/path").apply(request);
156+
157+
assertThat(result.uri().toString()).isEqualTo("http://localhost/new/path?foo%5B%5D=bar%5B%5D");
158+
}
159+
160+
}

0 commit comments

Comments
 (0)